ecore: add clean thread safety mecanism.

SVN revision: 62531
This commit is contained in:
Cedric BAIL 2011-08-17 09:43:49 +00:00
parent 1ec7bacc52
commit 7b047a49d7
2 changed files with 92 additions and 2 deletions

View File

@ -444,6 +444,34 @@ extern "C" {
*/
EAPI void *ecore_main_loop_thread_safe_call_sync(Ecore_Data_Cb callback, void *data);
/**
* @brief This function suspend the main loop in a know state
* @since 1.1.0
*
* @result EINA_TRUE if the main loop was suspended correcly.
*
* This function suspend the main loop in a know state, this let you
* use any EFL call you want after it return. Be carefull, the main loop
* is blocked until you call ecore_thread_main_loop_end(). This is
* the only sane way to achieve pseudo thread safety.
*
* Notice that until the main loop is blocked, the thread is blocked
* and their is noway around that.
*
* We still advise you, when possible, to use ecore_main_loop_thread_safe_call_async()
* as it will not block the thread nor the main loop.
*/
EAPI Eina_Bool ecore_thread_main_loop_begin(void);
/**
* @brief Unlock the main loop.
* @since 1.1.0
*
* After a call to ecore_thread_main_loop_begin(), you need to absolutly
* call ecore_thread_main_loop_end(), or you application will stay frozen.
*/
EAPI void ecore_thread_main_loop_end(void);
/**
* @}
*/

View File

@ -66,6 +66,7 @@ struct _Ecore_Safe_Call
Eina_Condition c;
Eina_Bool sync : 1;
Eina_Bool suspend : 1;
};
static void _ecore_main_loop_thread_safe_call(Ecore_Safe_Call *order);
@ -74,6 +75,11 @@ static void _thread_callback(void *data, void *buffer, unsigned int nbyte);
static Eina_List *_thread_cb = NULL;
static Ecore_Pipe *_thread_call = NULL;
static Eina_Lock _thread_safety;
static Eina_Bool _thread_loop = EINA_FALSE;
static Eina_Lock _thread_mutex;
static Eina_Condition _thread_cond;
Eina_Lock _ecore_main_loop_lock;
int _ecore_main_lock_count;
@ -151,9 +157,12 @@ ecore_init(void)
_ecore_time_init();
eina_lock_new(&_thread_safety);
eina_lock_new(&_ecore_main_loop_lock);
eina_lock_new(&_thread_mutex);
eina_condition_new(&_thread_cond, &_thread_mutex);
_thread_call = ecore_pipe_add(_thread_callback, NULL);
eina_lock_new(&_ecore_main_loop_lock);
#if HAVE_MALLINFO
if (getenv("ECORE_MEM_STAT"))
{
@ -265,6 +274,7 @@ ecore_main_loop_thread_safe_call_async(Ecore_Cb callback, void *data)
order->cb.async = callback;
order->data = data;
order->sync = EINA_FALSE;
order->suspend = EINA_FALSE;
_ecore_main_loop_thread_safe_call(order);
}
@ -290,6 +300,7 @@ ecore_main_loop_thread_safe_call_sync(Ecore_Data_Cb callback, void *data)
eina_lock_new(&order->m);
eina_condition_new(&order->c, &order->m);
order->sync = EINA_TRUE;
order->suspend = EINA_FALSE;
_ecore_main_loop_thread_safe_call(order);
@ -308,6 +319,44 @@ ecore_main_loop_thread_safe_call_sync(Ecore_Data_Cb callback, void *data)
return ret;
}
EAPI Eina_Bool
ecore_thread_main_loop_begin(void)
{
Ecore_Safe_Call *order;
if (eina_main_loop_is())
return EINA_FALSE;
order = malloc(sizeof (Ecore_Safe_Call));
if (!order) return EINA_FALSE;
eina_lock_new(&order->m);
eina_condition_new(&order->c, &order->m);
order->suspend = EINA_TRUE;
_ecore_main_loop_thread_safe_call(order);
eina_lock_take(&order->m);
eina_condition_wait(&order->c);
eina_lock_release(&order->m);
eina_main_loop_define();
_thread_loop = EINA_TRUE;
return EINA_TRUE;
}
EAPI void
ecore_thread_main_loop_end(void)
{
if (!_thread_loop) return ;
/* until we unlock the main loop, this thread has the main loop id */
if (!eina_main_loop_is()) return ;
eina_condition_broadcast(&_thread_cond);
}
EAPI void
ecore_print_warning(const char *function, const char *sparam)
{
@ -568,7 +617,20 @@ _thread_callback(void *data __UNUSED__,
EINA_LIST_FREE(callback, call)
{
if (call->sync)
if (call->suspend)
{
eina_condition_broadcast(&call->c);
eina_lock_take(&_thread_mutex);
eina_condition_wait(&_thread_cond);
eina_lock_release(&_thread_mutex);
eina_main_loop_define();
_thread_safe_cleanup(call);
free(call);
}
else if (call->sync)
{
call->data = call->cb.sync(call->data);
eina_condition_broadcast(&call->c);