ecore: delay promise fulfillment to next loop iteration.

This commit is contained in:
Cedric BAIL 2016-12-16 11:26:46 -08:00
parent b85332fc89
commit ca1762be21
3 changed files with 56 additions and 5 deletions

View File

@ -276,6 +276,7 @@ static void _ecore_main_win32_handlers_cleanup(void);
int in_main_loop = 0;
static Eina_List *_pending_futures = NULL;
static Eina_List *_pending_promises = NULL;
static unsigned char _ecore_exit_code = 0;
static int do_quit = 0;
static Ecore_Fd_Handler *fd_handlers = NULL;
@ -1598,6 +1599,7 @@ ecore_main_fd_handler_active_set(Ecore_Fd_Handler *fd_handler,
void
_ecore_main_shutdown(void)
{
Efl_Promise *promise;
Efl_Future *future;
if (in_main_loop)
@ -1611,6 +1613,9 @@ _ecore_main_shutdown(void)
EINA_LIST_FREE(_pending_futures, future)
efl_del(future);
EINA_LIST_FREE(_pending_promises, promise)
ecore_loop_promise_fulfill(promise);
while (fd_handlers)
{
Ecore_Fd_Handler *fdh;
@ -2235,7 +2240,7 @@ static void
_ecore_main_loop_iterate_internal(int once_only)
{
double next_time = -1.0;
Eo *f;
Eo *f, *p;
in_main_loop++;
@ -2243,6 +2248,10 @@ _ecore_main_loop_iterate_internal(int once_only)
EINA_LIST_FREE(_pending_futures, f)
efl_del(f);
/* and propagate all promise value */
EINA_LIST_FREE(_pending_promises, p)
ecore_loop_promise_fulfill(p);
/* expire any timers */
_efl_loop_timer_expired_timers_call(_ecore_time_loop_time);
@ -2933,6 +2942,17 @@ ecore_loop_future_unregister(Efl_Loop *l EINA_UNUSED, Efl_Future *f)
_pending_futures = eina_list_remove(_pending_futures, f);
}
void
ecore_loop_promise_register(Efl_Loop *l EINA_UNUSED, Efl_Promise *p)
{
_pending_promises = eina_list_append(_pending_promises, p);
}
void
ecore_loop_promise_unregister(Efl_Loop *l EINA_UNUSED, Efl_Promise *p)
{
_pending_promises = eina_list_remove(_pending_promises, p);
}
EFL_CALLBACKS_ARRAY_DEFINE(timeout,
{ EFL_LOOP_TIMER_EVENT_TICK, _efl_loop_timeout_cb },

View File

@ -370,6 +370,9 @@ extern Efl_Version _app_efl_version;
void ecore_loop_future_register(Efl_Loop *l, Efl_Future *f);
void ecore_loop_future_unregister(Efl_Loop *l, Efl_Future *f);
void ecore_loop_promise_register(Efl_Loop *l, Efl_Promise *p);
void ecore_loop_promise_unregister(Efl_Loop *l, Efl_Promise *p);
void ecore_loop_promise_fulfill(Efl_Promise *p);
// access to direct input cb
#define ECORE_EVAS_INTERNAL

View File

@ -35,6 +35,8 @@ struct _Efl_Promise_Data
} set;
Eina_Bool optional : 1;
Eina_Bool propagated : 1;
Eina_Bool nodelay : 1;
};
static void
@ -525,8 +527,9 @@ _efl_promise_future_get(Eo *obj, Efl_Promise_Data *pd EINA_UNUSED)
fd->promise = efl_data_xref(obj, EFL_PROMISE_CLASS, f);
fd->promise->futures = eina_list_append(fd->promise->futures, fd);
// The promise has already been fullfilled, prepare the propagation
if (fd->promise->message)
// The promise has already been fulfilled, prepare the propagation
if (fd->promise->message &&
fd->promise->propagated)
{
fd->message = fd->promise->message;
EINA_REFCOUNT_REF(fd->message);
@ -557,6 +560,8 @@ _efl_promise_propagate(Eo *obj, Efl_Promise_Data *pd)
Efl_Loop_Future_Data *f;
Eina_List *l, *ln;
pd->propagated = EINA_TRUE;
// By triggering this message, we are likely going to kill all future
// And a user of the promise may want to attach an event handler on the promise
// and destroy it, so delay that to after the loop is done.
@ -578,6 +583,14 @@ _efl_promise_propagate(Eo *obj, Efl_Promise_Data *pd)
efl_unref(obj);
}
void
ecore_loop_promise_fulfill(Eo *obj)
{
Efl_Promise_Data *pd = efl_data_scope_get(obj, EFL_PROMISE_CLASS);
_efl_promise_propagate(obj, pd);
}
static void
_efl_promise_value_set(Eo *obj, Efl_Promise_Data *pd, void *v, Eina_Free_Cb free_cb)
{
@ -599,7 +612,10 @@ _efl_promise_value_set(Eo *obj, Efl_Promise_Data *pd, void *v, Eina_Free_Cb free
EINA_REFCOUNT_INIT(message);
pd->message = message;
_efl_promise_propagate(obj, pd);
if (pd->nodelay)
_efl_promise_propagate(obj, pd);
else
ecore_loop_promise_register(efl_provider_find(obj, EFL_LOOP_CLASS), obj);
}
static void
@ -621,7 +637,10 @@ _efl_promise_failed_set(Eo *obj, Efl_Promise_Data *pd, Eina_Error err)
EINA_REFCOUNT_INIT(message);
pd->message = message;
_efl_promise_propagate(obj, pd);
if (pd->nodelay)
_efl_promise_propagate(obj, pd);
else
ecore_loop_promise_register(efl_provider_find(obj, EFL_LOOP_CLASS), obj);
}
static void
@ -665,6 +684,8 @@ _efl_promise_efl_object_constructor(Eo *obj, Efl_Promise_Data *pd)
static void
_efl_promise_efl_object_destructor(Eo *obj, Efl_Promise_Data *pd)
{
pd->nodelay = EINA_TRUE;
// Unref refcounted structure
if (!pd->message && pd->futures)
{
@ -672,6 +693,13 @@ _efl_promise_efl_object_destructor(Eo *obj, Efl_Promise_Data *pd)
efl_promise_failed_set(obj, EINA_ERROR_FUTURE_CANCEL);
}
if (pd->message &&
!pd->propagated)
{
ecore_loop_promise_unregister(efl_provider_find(obj, EFL_LOOP_CLASS), obj);
_efl_promise_propagate(obj, pd);
}
if (pd->message)
{
EINA_REFCOUNT_UNREF(pd->message)