ecore: add ecore_thread_wait and necessary infrastructure.

This enable the possibility to block the main loop until a
specific thread is done. It may trigger still process ending
of other thread during that function call, but not any other
type of event (timer, animator, idler, ... are all ignored).
This commit is contained in:
Cedric BAIL 2015-01-07 16:42:24 +01:00
parent 2cae004592
commit e5ddfb4b2b
3 changed files with 101 additions and 0 deletions

View File

@ -385,6 +385,19 @@ EAPI void ecore_main_loop_thread_safe_call_async(Ecore_Cb callback, void *data);
*/
EAPI void *ecore_main_loop_thread_safe_call_sync(Ecore_Data_Cb callback, void *data);
/**
* @brief Wait for the next thread call in the main loop.
* @since 1.13.0
*
* @param wait How long to wait for this callback to be called
*
* Note: This function should only be called in the main loop
* and will actually block the main loop until either a call
* is triggered from a thread or the time specified by wait has
* passed.
*/
EAPI void ecore_main_loop_thread_safe_call_wait(double wait);
/**
* @brief This function suspend the main loop in a know state
* @since 1.1.0
@ -1818,6 +1831,15 @@ EAPI Ecore_Thread *ecore_thread_feedback_run(Ecore_Thread_Cb func_heavy, Ecore_T
*/
EAPI Eina_Bool ecore_thread_cancel(Ecore_Thread *thread);
/**
* @brief Block the main loop until the thread execution is over.
*
* @param thread The thread to wait on.
* @param wait Maximum time to wait before exiting anyway.
* @return EINA_TRUE if the thread execution is over.
*/
EAPI Eina_Bool ecore_thread_wait(Ecore_Thread *thread, double wait);
/**
* Checks if a thread is pending cancellation
*

View File

@ -583,6 +583,12 @@ ecore_main_loop_thread_safe_call_sync(Ecore_Data_Cb callback,
return ret;
}
EAPI void
ecore_main_loop_thread_safe_call_wait(double wait)
{
ecore_pipe_wait(_thread_call, 1, wait);
}
EAPI int
ecore_thread_main_loop_begin(void)
{

View File

@ -733,6 +733,79 @@ ecore_thread_cancel(Ecore_Thread *thread)
return EINA_FALSE;
}
typedef struct _Ecore_Thread_Waiter Ecore_Thread_Waiter;
struct _Ecore_Thread_Waiter
{
Ecore_Thread_Cb func_cancel;
Ecore_Thread_Cb func_end;
const void *data;
};
static void
_ecore_thread_wait_reset(Ecore_Thread_Waiter *waiter,
Ecore_Pthread_Worker *worker)
{
worker->data = waiter->data;
worker->func_cancel = waiter->func_cancel;
worker->func_end = waiter->func_end;
// The waiter will be checked by _wait, NULL meaning it is done
waiter->func_end = NULL;
waiter->func_cancel = NULL;
waiter->data = NULL;
}
static void
_ecore_thread_wait_cancel(void *data, Ecore_Thread *thread)
{
Ecore_Pthread_Worker *worker = (Ecore_Pthread_Worker*) thread;
Ecore_Thread_Waiter *waiter = data;
waiter->func_cancel((void*) waiter->data, thread);
_ecore_thread_wait_reset(waiter, worker);
}
static void
_ecore_thread_wait_end(void *data, Ecore_Thread *thread)
{
Ecore_Pthread_Worker *worker = (Ecore_Pthread_Worker*) thread;
Ecore_Thread_Waiter *waiter = data;
waiter->func_end((void*) waiter->data, thread);
_ecore_thread_wait_reset(waiter, worker);
}
EAPI Eina_Bool
ecore_thread_wait(Ecore_Thread *thread, double wait)
{
Ecore_Pthread_Worker *worker = (Ecore_Pthread_Worker*) thread;
Ecore_Thread_Waiter waiter;
if (!thread) return ;
waiter.data = worker->data;
waiter.func_end = worker->func_end;
waiter.func_cancel = worker->func_cancel;
// Now trick the thread to call the wrapper function
worker->data = &waiter;
worker->func_cancel = _ecore_thread_wait_cancel;
worker->func_end = _ecore_thread_wait_end;
while (waiter.data)
{
double start, end;
start = ecore_time_get();
ecore_main_loop_thread_safe_call_wait(wait);
end = ecore_time_get();
wait -= end - start;
if (wait <= 0) break;
}
return (waiter.data == NULL) ? EINA_TRUE : EINA_FALSE;
}
EAPI Eina_Bool
ecore_thread_check(Ecore_Thread *thread)
{