From: cedric Date: Tue, 16 Aug 2011 14:35:00 +0000 (+0000) Subject: ecore: add ecore_main_loop_thread_safe_call_sync and rename ecore_main_loop_thread_sa... X-Git-Tag: accepted/2.0/20130306.224007~156^2~137 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=1e13d4e781161074087ac66cabd357bc063ef008;p=profile%2Fivi%2Fecore.git ecore: add ecore_main_loop_thread_safe_call_sync and rename ecore_main_loop_thread_safe_call. git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/ecore@62513 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33 --- diff --git a/ChangeLog b/ChangeLog index 1dc8bdd..3549497 100644 --- a/ChangeLog +++ b/ChangeLog @@ -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. diff --git a/src/lib/ecore/Ecore.h b/src/lib/ecore/Ecore.h index b8f87c6..bb624b2 100644 --- a/src/lib/ecore/Ecore.h +++ b/src/lib/ecore/Ecore.h @@ -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); /** * @} @@ -484,12 +508,6 @@ extern "C" { 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. */ diff --git a/src/lib/ecore/ecore.c b/src/lib/ecore/ecore.c index 7af5d4d..7ceea39 100644 --- a/src/lib/ecore/ecore.c +++ b/src/lib/ecore/ecore.c @@ -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 @@ -485,6 +531,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__, unsigned int nbyte __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); + } } }