ecore: add ecore_main_loop_thread_safe_call_sync and rename ecore_main_loop_thread_safe_call.

SVN revision: 62513
This commit is contained in:
Cedric BAIL 2011-08-16 14:35:00 +00:00
parent bf958ebbd7
commit 1ca5e18738
3 changed files with 119 additions and 21 deletions

View File

@ -271,10 +271,13 @@
2011-07-28 Cedric Bail
* Add ecore_main_loop_thread_safe_call.
* Add ecore_main_loop_thread_safe_call_async.
2011-07-26 Carsten Haitzler (The Rasterman)
* Make ecore-evas give more errors on stderr when engines are
not found.
2011-08-16 Cedric Bail
* Add ecore_main_loop_thread_safe_call_sync.

View File

@ -404,8 +404,15 @@ extern "C" {
*/
typedef void (*Ecore_Cb) (void *data);
/**
* @typedef Ecore_Data_Cb Ecore_Data_Cb
* A callback which is used to return data to the main function
*/
typedef void *(*Ecore_Data_Cb) (void *data);
/**
* @brief Call callback in the main loop.
* @brief Call callback asynchronously in the main loop.
* @since 1.1.0
*
* @param callback The callback to call in the main loop
* @param data The data to give to that call back
@ -418,7 +425,24 @@ extern "C" {
* in the thread, it is owned by the main loop and you callback should take
* care of freeing it if necessary.
*/
EAPI void ecore_main_loop_thread_safe_call(Ecore_Cb callback, void *data);
EAPI void ecore_main_loop_thread_safe_call_async(Ecore_Cb callback, void *data);
/**
* @brief Call callback synchronously in the main loop.
* @since 1.1.0
*
* @param callback The callback to call in the main loop
* @param data The data to give to that call back
* @return the value returned by the callback in the main loop
*
* For all call that need to happen in the main loop (most EFL functions do),
* this helper function provide the infrastructure needed to do it safely
* by avoind dead lock, race condition and properly wake up the main loop.
*
* Remember this function will block until the callback is executed in the
* main loop. It can take time and you have no guaranty about the timeline.
*/
EAPI void *ecore_main_loop_thread_safe_call_sync(Ecore_Data_Cb callback, void *data);
/**
* @}
@ -483,12 +507,6 @@ extern "C" {
typedef struct _Ecore_Event_Signal_Power Ecore_Event_Signal_Power; /**< Power signal event */
typedef struct _Ecore_Event_Signal_Realtime Ecore_Event_Signal_Realtime; /**< Realtime signal event */
/**
* @typedef Ecore_Data_Cb Ecore_Data_Cb
* A callback which is used to return data to the main function
*/
typedef void *(*Ecore_Data_Cb) (void *data);
/**
* @typedef Ecore_Filter_Cb
* A callback used for filtering events from the main loop.

View File

@ -56,10 +56,20 @@ int _ecore_fps_debug = 0;
typedef struct _Ecore_Safe_Call Ecore_Safe_Call;
struct _Ecore_Safe_Call
{
Ecore_Cb cb;
union {
Ecore_Cb async;
Ecore_Data_Cb sync;
} cb;
void *data;
Eina_Lock m;
Eina_Condition c;
Eina_Bool sync : 1;
};
static void _ecore_main_loop_thread_safe_call(Ecore_Safe_Call *order);
static void _thread_safe_cleanup(void *data);
static void _thread_callback(void *data, void *buffer, unsigned int nbyte);
static Eina_List *_thread_cb = NULL;
static Ecore_Pipe *_thread_call = NULL;
@ -234,12 +244,14 @@ unlock:
* @}
*/
static int wakeup = 42;
EAPI void
ecore_main_loop_thread_safe_call(Ecore_Cb callback, void *data)
ecore_main_loop_thread_safe_call_async(Ecore_Cb callback, void *data)
{
Ecore_Safe_Call *order;
int wakeup = 42;
Eina_Bool count;
if (!callback) return ;
if (eina_main_loop_is())
{
@ -250,16 +262,50 @@ ecore_main_loop_thread_safe_call(Ecore_Cb callback, void *data)
order = malloc(sizeof (Ecore_Safe_Call));
if (!order) return ;
order->cb = callback;
order->cb.async = callback;
order->data = data;
order->sync = EINA_FALSE;
eina_lock_take(&_thread_safety);
_ecore_main_loop_thread_safe_call(order);
}
count = _thread_cb ? 0 : 1;
_thread_cb = eina_list_append(_thread_cb, order);
if (count) ecore_pipe_write(_thread_call, &wakeup, sizeof (int));
EAPI void *
ecore_main_loop_thread_safe_call_sync(Ecore_Data_Cb callback, void *data)
{
Ecore_Safe_Call *order;
void *ret;
eina_lock_release(&_thread_safety);
if (!callback) return NULL;
if (eina_main_loop_is())
{
return callback(data);
}
order = malloc(sizeof (Ecore_Safe_Call));
if (!order) return NULL;
order->cb.sync = callback;
order->data = data;
eina_lock_new(&order->m);
eina_condition_new(&order->c, &order->m);
order->sync = EINA_TRUE;
_ecore_main_loop_thread_safe_call(order);
eina_lock_take(&order->m);
eina_condition_wait(&order->c);
eina_lock_release(&order->m);
ret = order->data;
order->sync = EINA_FALSE;
order->cb.async = _thread_safe_cleanup;
order->data = order;
_ecore_main_loop_thread_safe_call(order);
return ret;
}
EAPI void
@ -484,6 +530,29 @@ _ecore_memory_statistic(__UNUSED__ void *data)
#endif
static void
_ecore_main_loop_thread_safe_call(Ecore_Safe_Call *order)
{
Eina_Bool count;
eina_lock_take(&_thread_safety);
count = _thread_cb ? 0 : 1;
_thread_cb = eina_list_append(_thread_cb, order);
if (count) ecore_pipe_write(_thread_call, &wakeup, sizeof (int));
eina_lock_release(&_thread_safety);
}
static void
_thread_safe_cleanup(void *data)
{
Ecore_Safe_Call *call = data;
eina_condition_free(&call->c);
eina_lock_free(&call->m);
}
static void
_thread_callback(void *data __UNUSED__,
void *buffer __UNUSED__,
@ -499,7 +568,15 @@ _thread_callback(void *data __UNUSED__,
EINA_LIST_FREE(callback, call)
{
call->cb(call->data);
free(call);
if (call->sync)
{
call->data = call->cb.sync(call->data);
eina_condition_broadcast(&call->c);
}
else
{
call->cb.async(call->data);
free(call);
}
}
}