ecore: add a prototype ecore_thread helper with Efl_Promise/Efl_Future coupled.

This commit is contained in:
Cedric BAIL 2016-09-26 16:35:52 -07:00
parent c4c95adc6b
commit 6c514dddb3
2 changed files with 181 additions and 0 deletions

View File

@ -3124,6 +3124,10 @@ EAPI Ecore_Thread* ecore_thread_promise_run(Ecore_Thread_Promise_Cb func_heavy,
const void* data,
Eina_Promise** promise);
typedef void (*Ecore_Thread_Future_Cb)(const void *data, Eo *promise, Ecore_Thread *thread);
EAPI Efl_Future *ecore_thread_future_run(Ecore_Thread_Future_Cb heavy, const void *data, Eina_Free_Cb free_cb);
#endif
#ifdef __cplusplus

View File

@ -1458,3 +1458,180 @@ ecore_thread_global_data_wait(const char *key,
if (ret) return ret->data;
return NULL;
}
typedef struct _Ecore_Thread_Set Ecore_Thread_Set;
struct _Ecore_Thread_Set
{
Eo *obj;
union {
struct {
void *v;
Eina_Free_Cb free_cb;
} value;
Eina_Error error;
} u;
Eina_Bool success;
};
static void
_ecore_thread_main_loop_set(void *data)
{
Ecore_Thread_Set *dt = data;
if (dt->success)
efl_promise_value_set(efl_super(dt->obj, EFL_OBJECT_OVERRIDE_CLASS),
dt->u.value.v, dt->u.value.free_cb);
else
efl_promise_failed_set(efl_super(dt->obj, EFL_OBJECT_OVERRIDE_CLASS),
dt->u.error);
efl_unref(dt->obj);
free(dt);
}
static Ecore_Thread_Set *
_ecore_thread_set_new(Eo *obj)
{
Ecore_Thread_Set *dt;
dt = calloc(1, sizeof (Ecore_Thread_Set));
if (!dt) return NULL;
dt->obj = efl_ref(obj);
return dt;
}
static void
_ecore_thread_value_set(Eo *obj, const void *data EINA_UNUSED, void *v, Eina_Free_Cb free_cb)
{
Ecore_Thread_Set *dt;
dt = _ecore_thread_set_new(obj);
if (!dt) return ;
dt->success = EINA_TRUE;
dt->u.value.v = v;
dt->u.value.free_cb = free_cb;
ecore_main_loop_thread_safe_call_async(_ecore_thread_main_loop_set, dt);
}
static void
_ecore_thread_failed_set(Eo *obj, const void *data EINA_UNUSED, Eina_Error err)
{
Ecore_Thread_Set *dt;
dt = _ecore_thread_set_new(obj);
if (!dt) return ;
dt->success = EINA_FALSE;
dt->u.error = err;
ecore_main_loop_thread_safe_call_async(_ecore_thread_main_loop_set, dt);
}
typedef struct _Ecore_Thread_Progress Ecore_Thread_Progress;
struct _Ecore_Thread_Progress
{
Eo *obj;
const void *p;
};
static void *
_ecore_thread_progress_sync(void *data)
{
Ecore_Thread_Progress *p = data;
efl_promise_progress_set(efl_super(p->obj, EFL_OBJECT_OVERRIDE_CLASS), p->p);
return NULL;
}
static void
_ecore_thread_progress_set(Eo *obj, const void *data EINA_UNUSED, const void *p)
{
Ecore_Thread_Progress ip = { efl_ref(obj), p };
ecore_main_loop_thread_safe_call_sync(_ecore_thread_progress_sync, &ip);
efl_unref(obj);
}
static void
_ecore_thread_future_heavy(void *dp, Ecore_Thread *thread)
{
Ecore_Thread_Future_Cb heavy;
const void *data;
Eo *p = dp;
heavy = efl_key_data_get(p, "_ecore_thread.heavy");
data = efl_key_data_get(p, "_ecore_thread.data");
heavy(data, p, thread);
}
static void
_ecore_thread_future_end(void *dp, Ecore_Thread *thread EINA_UNUSED)
{
Eina_Free_Cb free_cb;
void *data;
Eo *p = dp;
free_cb = efl_key_data_get(p, "_ecore_thread.free_cb");
data = efl_key_data_get(p, "_ecore_thread.data");
if (free_cb) free_cb(data);
efl_del(p);
}
static void
_ecore_thread_future_none(void *data, const Efl_Event *ev EINA_UNUSED)
{
Ecore_Thread *t = data;
// Cancelling thread if there is nobody listening on the promise anymore
ecore_thread_cancel(t);
}
EAPI Efl_Future *
ecore_thread_future_run(Ecore_Thread_Future_Cb heavy, const void *data, Eina_Free_Cb free_cb)
{
Ecore_Thread *t;
Eo *p;
if (!heavy) return NULL;
EFL_OPS_DEFINE(thread_safe_call,
EFL_OBJECT_OP_FUNC(efl_promise_value_set, _ecore_thread_value_set),
EFL_OBJECT_OP_FUNC(efl_promise_failed_set, _ecore_thread_failed_set),
EFL_OBJECT_OP_FUNC(efl_promise_progress_set, _ecore_thread_progress_set));
efl_domain_current_push(EFL_ID_DOMAIN_SHARED);
efl_wref_add(efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get()), &p);
if (!p) goto end;
efl_object_override(p, &thread_safe_call);
efl_key_data_set(p, "_ecore_thread.data", data);
efl_key_data_set(p, "_ecore_thread.free_cb", free_cb);
efl_key_data_set(p, "_ecore_thread.heavy", heavy);
t = ecore_thread_run(_ecore_thread_future_heavy,
_ecore_thread_future_end,
_ecore_thread_future_end,
p);
if (p)
{
efl_event_callback_add(p, EFL_PROMISE_EVENT_FUTURE_NONE, _ecore_thread_future_none, t);
efl_wref_del(p, &p);
}
end:
efl_domain_current_pop();
return p ? efl_promise_future_get(p) : NULL;
}