On Tue, 8 Mar 2016 14:01:28 +0000 Tom Hacohen <t...@osg.samsung.com> said:
> I real want to keep my temper, but seriously WHAT THE FUCK? > > Why wasn't this discussed?! Mentioned? Something? > > The dlsym to call ecore functions from Eo is bad enough to revert this > immediately, but also the implementation in Eolian is wrong according to > Daniel, and not to mention, doesn't follow the rest of the Eolian > conventions of lower case types. thanks tom - yeah. dlsym ... bad. this needs to be resolved properly. if promises are a core thing in EO then they need to be in EO. not in ecore. a promise will need the ability to be DRIVEN from a loop (e.g. when data/event comes in)... > Why didn't you consult with Daniel about Eolian and me about Eo before > just sneaking it in with the "ecore" prefix with nothing in the commit > message. We both missed it until we manually reviewed Eo jsust now. > > I don't even understand why there should be native eo support for this, > and why this isn't just implemented like literally everything else that > we have in the EFL, and the commit message doesn't do anything to > explain that. This is just wrong. then they'd have to be eo objects that you return - i remember asking if promises were to be eo objects because i thought it'd be implemented just as more "eo stuff". but if it needs special casing for bindings then it needs doing "right" as you say. :) > Honestly, WTF. > > -- > Tom. > > > On 06/03/16 20:57, Felipe Magno de Almeida wrote: > > felipealmeida pushed a commit to branch master. > > > > http://git.enlightenment.org/core/efl.git/commit/?id=f9ba80ab33e0b94dad7ec103e6d261a644f7835f > > > > commit f9ba80ab33e0b94dad7ec103e6d261a644f7835f > > Author: Felipe Magno de Almeida <fel...@expertisesolutions.com.br> > > Date: Sun Mar 6 17:39:20 2016 -0300 > > > > ecore: Create Promises > > > > Add a promise object that allows Eolian interface to include promises > > as a way to have asynchronous value return and composibility. > > > > The usage is like this in a .eo file: > > > > class Foo { > > methods { > > bar { > > params { > > promise: Promise<int>; > > } > > } > > } > > } > > > > Which will create the following API interface: > > > > void foo_bar(Ecore_Promise** promise); > > > > and the equivalent declaration for implementation. > > > > However, the API function will instantiate the Promise for the > > user and the implementer of the class. > > --- > > src/Makefile_Ecore.am | 5 +- > > src/bin/eolian/eo_generator.c | 30 ++- > > src/lib/ecore/Ecore.h | 1 + > > src/lib/ecore/ecore_promise.c | 452 +++++++++++++++++++++++++++++++ > > ++++ src/lib/ecore/ecore_promise.h | 136 +++++++++++ > > src/lib/eo/Eo.h | 63 +++-- > > src/lib/eolian/eo_lexer.c | 3 +- > > src/lib/eolian/eo_lexer.h | 6 +- > > src/lib/eolian/eo_parser.c | 2 +- > > src/tests/ecore/ecore_suite.c | 1 + > > src/tests/ecore/ecore_suite.h | 1 + > > src/tests/ecore/ecore_test_promise.c | 364 ++++++++++++++++++++++++++++ > > 12 files changed, 1042 insertions(+), 22 deletions(-) > > > > diff --git a/src/Makefile_Ecore.am b/src/Makefile_Ecore.am > > index 49936af..79ac16c 100644 > > --- a/src/Makefile_Ecore.am > > +++ b/src/Makefile_Ecore.am > > @@ -47,7 +47,8 @@ lib/ecore/Ecore.h \ > > lib/ecore/Ecore_Common.h \ > > lib/ecore/Ecore_Legacy.h \ > > lib/ecore/Ecore_Eo.h \ > > -lib/ecore/Ecore_Getopt.h > > +lib/ecore/Ecore_Getopt.h \ > > +lib/ecore/ecore_promise.h > > > > nodist_installed_ecoremainheaders_DATA = \ > > $(ecore_eolian_h) > > @@ -72,6 +73,7 @@ lib/ecore/ecore_timer.c \ > > lib/ecore/ecore_thread.c \ > > lib/ecore/ecore_throttle.c \ > > lib/ecore/ecore_exe.c \ > > +lib/ecore/ecore_promise.c \ > > lib/ecore/ecore_exe_private.h \ > > lib/ecore/ecore_private.h > > > > @@ -199,6 +201,7 @@ tests/ecore/ecore_test_animator.c \ > > tests/ecore/ecore_test_ecore_thread_eina_thread_queue.c \ > > tests/ecore/ecore_test_ecore_input.c \ > > tests/ecore/ecore_test_ecore_file.c \ > > +tests/ecore/ecore_test_promise.c \ > > tests/ecore/ecore_suite.h > > > > tests_ecore_ecore_suite_CPPFLAGS = -I$(top_builddir)/src/lib/efl \ > > diff --git a/src/bin/eolian/eo_generator.c b/src/bin/eolian/eo_generator.c > > index a97f2f0..4810658 100644 > > --- a/src/bin/eolian/eo_generator.c > > +++ b/src/bin/eolian/eo_generator.c > > @@ -311,6 +311,9 @@ eo_bind_func_generate(const Eolian_Class *class, const > > Eolian_Function *funcid, if (ftype != EOLIAN_PROP_GET && ftype != > > EOLIAN_PROP_SET) ftype = eolian_function_type_get(funcid); Eina_Bool > > is_prop = (ftype == EOLIAN_PROP_GET || ftype == EOLIAN_PROP_SET); > > > > + Eina_Bool has_promise = EINA_FALSE; > > + const char* promise_param_name = NULL; > > + const char* promise_value_type = NULL; > > Eina_Bool need_implementation = EINA_TRUE; > > if (!impl_env && eolian_function_is_virtual_pure(funcid, ftype)) > > need_implementation = EINA_FALSE; > > > > @@ -337,9 +340,11 @@ eo_bind_func_generate(const Eolian_Class *class, const > > Eolian_Function *funcid, if (eina_iterator_next(itr, &data) && ! > > eina_iterator_next(itr, &data2)) { > > Eolian_Function_Parameter *param = data; > > + const char* rettype_str = NULL; > > rettypet = eolian_parameter_type_get(param); > > var_as_ret = EINA_TRUE; > > default_ret_val = eolian_parameter_default_value_get > > (param); > > + eina_stringshare_del(rettype_str); > > } > > eina_iterator_free(itr); > > } > > @@ -375,9 +380,24 @@ eo_bind_func_generate(const Eolian_Class *class, const > > Eolian_Function *funcid, const char *ptype = eolian_type_c_type_get(ptypet); > > Eolian_Parameter_Dir pdir = eolian_parameter_direction_get > > (param); Eina_Bool had_star = !!strchr(ptype, '*'); > > + > > + if(!has_promise && !strcmp(ptype, "Ecore_Promise *")) > > + { > > + Eina_Iterator* promise_values; > > + has_promise = EINA_TRUE; > > + promise_param_name = eina_stringshare_add(pname); > > + promise_values = eolian_type_subtypes_get > > (eolian_type_base_type_get(ptypet)); > > + Eolian_Type* subtype; > > + if(eina_iterator_next(promise_values, (void**)&subtype)) > > + promise_value_type = eolian_type_c_type_get(subtype); > > + } > > + > > if (ftype == EOLIAN_UNRESOLVED || ftype == EOLIAN_METHOD) > > add_star = (pdir == EOLIAN_OUT_PARAM || pdir == EOLIAN_INOUT_PARAM); if > > (eina_strbuf_length_get(params)) eina_strbuf_append(params, ", "); > > - eina_strbuf_append_printf(params, "%s", pname); > > + if(has_promise) > > + eina_strbuf_append_printf(params, "%s", "&__eo_promise"); > > + else > > + eina_strbuf_append_printf(params, "%s", pname); > > eina_strbuf_append_printf(full_params, ", %s%s%s%s%s", > > ptype, had_star?"":" ", add_star?"*":"", pname, > > is_empty && !dflt_value ?" EINA_UNUSED":""); if (is_auto) > > @@ -511,8 +531,8 @@ eo_bind_func_generate(const Eolian_Class *class, const > > Eolian_Function *funcid, Eina_Bool ret_is_void = (!rettype || !strcmp > > (rettype, "void")); _class_func_env_create(class, eolian_function_name_get > > (funcid), ftype, &func_env); eina_strbuf_append_printf(eo_func_decl, > > - "EOAPI EO_%sFUNC_BODY%s%s(%s", > > - ret_is_void?"VOID_":"", has_params?"V":"", > > + "EOAPI EO_%sFUNC_%sBODY%s%s(%s", > > + ret_is_void?"VOID_":"", has_promise?"PROMISE_":"", > > has_params?"V":"", (ftype == EOLIAN_PROP_GET || > > eolian_function_object_is_const(funcid) || > > eolian_function_is_class(funcid))?"_CONST":"", > > func_env.lower_eo_func); @@ -535,6 +555,10 @@ eo_bind_func_generate(const > > Eolian_Class *class, const Eolian_Function *funcid, eina_stringshare_del > > (string); } > > } > > + if (has_promise) > > + { > > + eina_strbuf_append_printf(eo_func_decl, ", %s, %s", > > promise_param_name, promise_value_type); > > + } > > if (has_params) > > { > > eina_strbuf_replace_all(full_params, " EINA_UNUSED", ""); > > diff --git a/src/lib/ecore/Ecore.h b/src/lib/ecore/Ecore.h > > index e843038..df28b64 100644 > > --- a/src/lib/ecore/Ecore.h > > +++ b/src/lib/ecore/Ecore.h > > @@ -356,6 +356,7 @@ extern "C" { > > #endif > > #ifdef EFL_EO_API_SUPPORT > > #include "Ecore_Eo.h" > > +#include "ecore_promise.h" > > #endif > > > > #ifdef __cplusplus > > diff --git a/src/lib/ecore/ecore_promise.c b/src/lib/ecore/ecore_promise.c > > new file mode 100644 > > index 0000000..c55d519 > > --- /dev/null > > +++ b/src/lib/ecore/ecore_promise.c > > @@ -0,0 +1,452 @@ > > +#ifdef HAVE_CONFIG_H > > +#include <config.h> > > +#endif > > + > > +#include <Eina.h> > > +#include <Ecore.h> > > + > > +#include <assert.h> > > + > > +typedef void(*Ecore_Promise_Free_Cb)(void*); > > + > > +struct _Ecore_Promise_Then_Cb > > +{ > > + EINA_INLIST; > > + > > + Ecore_Promise_Cb callback; > > + void* data; > > +}; > > + > > +struct _Ecore_Promise > > +{ > > + Eina_Lock lock; > > + Eina_Condition condition; > > + Eina_Bool has_finished : 1; > > + Eina_Bool has_errored : 1; > > + Eina_Bool has_pending_call : 1; > > + Eina_Bool is_then_calls_manual : 1; > > + Eina_Error error; > > + size_t value_size; > > + int ref; > > + > > + struct _Ecore_Promise_Then_Cb then_callbacks; > > + Ecore_Promise_Free_Cb free_cb; > > + > > + char value[]; > > +}; > > + > > +struct _Ecore_Promise_Thread_Data > > +{ > > + const void* data; > > + Ecore_Promise_Thread_Cb func_blocking; > > + Ecore_Promise* promise; > > +}; > > + > > +typedef struct _Ecore_Promise_Iterator _Ecore_Promise_Iterator; > > +typedef struct _Ecore_Promise_Success_Iterator > > _Ecore_Promise_Success_Iterator; +typedef struct > > _Ecore_Promise_Failure_Iterator _Ecore_Promise_Failure_Iterator; +struct > > _Ecore_Promise_Iterator +{ > > + Eina_Iterator* success_iterator; > > + Eina_Iterator* failure_iterator; > > + struct _Ecore_Promise_Success_Iterator > > + { > > + Eina_Iterator success_iterator_impl; > > + struct _Ecore_Promise_Failure_Iterator > > + { > > + Eina_Iterator failure_iterator_impl; > > + unsigned int promise_index; > > + unsigned int num_promises; > > + unsigned int promises_finished; > > + Ecore_Promise* promises[]; > > + } data; > > + } data; > > +}; > > + > > +static void _ecore_promise_lock_take(Ecore_Promise* promise); > > +static void _ecore_promise_lock_release(Ecore_Promise* promise); > > +static void _ecore_promise_finish(Ecore_Promise* promise); > > +static void _ecore_promise_then_calls(Ecore_Promise* promise); > > +static void _ecore_promise_unsafe_ref(Ecore_Promise const* promise); > > +static void _ecore_promise_unsafe_unref(Ecore_Promise const* promise); > > +static void _ecore_promise_unsafe_free_unref(Ecore_Promise const* promise); > > +static Eina_Bool _ecore_promise_unlock_unsafe_free_unref(Ecore_Promise > > const* promise); + > > +static void _ecore_promise_iterator_setup(_Ecore_Promise_Iterator* > > iterator, Eina_Array* promises); + > > +static void _ecore_promise_thread_end(void* data, Ecore_Thread* thread > > EINA_UNUSED) +{ > > + struct _Ecore_Promise_Thread_Data* p = data; > > + _ecore_promise_lock_take(p->promise); > > + if(p->promise->has_finished) > > + { > > + p->promise->has_pending_call = EINA_FALSE; > > + if(!_ecore_promise_unlock_unsafe_free_unref(p->promise)) > > + _ecore_promise_then_calls(p->promise); > > + } > > + else > > + { > > + p->promise->is_then_calls_manual = EINA_FALSE; > > + p->promise->has_pending_call = EINA_FALSE; > > + _ecore_promise_unlock_unsafe_free_unref(p->promise); > > + } > > + free(data); > > +} > > + > > +static void > > +_ecore_promise_thread_blocking(void* data, Ecore_Thread* thread > > EINA_UNUSED) +{ > > + struct _Ecore_Promise_Thread_Data* p = data; > > + (p->func_blocking)(p->data, p->promise); > > +} > > + > > +static void > > +_ecore_promise_then_calls(Ecore_Promise* promise) > > +{ > > + _ecore_promise_lock_take(promise); > > + struct _Ecore_Promise_Then_Cb then_callbacks = promise->then_callbacks; > > + memset(&promise->then_callbacks, 0, sizeof(promise->then_callbacks)); > > + promise->has_pending_call = EINA_FALSE; > > + _ecore_promise_lock_release(promise); > > + > > + struct _Ecore_Promise_Then_Cb* callback; > > + > > + if(then_callbacks.callback) > > + { > > + (*then_callbacks.callback)(then_callbacks.data, &promise->value[0]); > > + _ecore_promise_unsafe_free_unref(promise); > > + } > > + > > + if(EINA_INLIST_GET(&then_callbacks)->next) > > + { > > + Eina_Inlist* list2; > > + EINA_INLIST_FOREACH_SAFE(EINA_INLIST_GET(&then_callbacks)->next, > > list2, callback) > > + { > > + if(callback->callback) > > + { > > + (*callback->callback)(callback->data, promise); > > + } > > + _ecore_promise_unsafe_free_unref(promise); > > + } > > + } > > +} > > + > > +Ecore_Promise* ecore_promise_thread_run(Ecore_Promise_Thread_Cb > > func_blocking, const void* data, size_t value_size) +{ > > + struct _Ecore_Promise_Thread_Data *new_data = malloc(sizeof(struct > > _Ecore_Promise_Thread_Data)); > > + new_data->data = data; > > + new_data->func_blocking = func_blocking; > > + new_data->promise = ecore_promise_add(value_size); > > + new_data->promise->is_then_calls_manual = EINA_TRUE; > > + new_data->promise->has_pending_call = EINA_TRUE; > > + ecore_promise_ref(new_data->promise); > > + ecore_thread_run(&_ecore_promise_thread_blocking, > > &_ecore_promise_thread_end, NULL, new_data); > > + return new_data->promise; > > +} > > + > > +Ecore_Promise* ecore_promise_add(int value_size) > > +{ > > + Ecore_Promise* p = malloc(sizeof(Ecore_Promise) + value_size); > > + eina_lock_new(&p->lock); > > + eina_condition_new(&p->condition, &p->lock); > > + p->has_finished = p->has_errored = p->has_pending_call = > > p->is_then_calls_manual = EINA_FALSE; > > + p->ref = 1; > > + memset(&p->then_callbacks, 0, sizeof(p->then_callbacks)); > > + p->value_size = value_size; > > + p->free_cb = NULL; > > + return p; > > +} > > + > > +static void _ecore_promise_del(Ecore_Promise* promise) > > +{ > > + if(promise->free_cb) > > + promise->free_cb((void*)&promise->value[0]); > > + > > + eina_lock_free(&promise->lock); > > + eina_condition_free(&promise->condition); > > +} > > + > > +void* ecore_promise_buffer_get(Ecore_Promise* promise) > > +{ > > + return &promise->value[0]; > > +} > > + > > +void* ecore_promise_value_get(Ecore_Promise const* promise) > > +{ > > + _ecore_promise_lock_take((Ecore_Promise*)promise); > > + _ecore_promise_unsafe_ref(promise); > > + while(!promise->has_finished) > > + { > > + eina_condition_wait((Eina_Condition*)&promise->condition); > > + } > > + > > + void* v = (void*)(promise->value_size && !promise->has_errored ? > > &promise->value[0] : NULL); > > + _ecore_promise_unsafe_unref(promise); > > + _ecore_promise_lock_release((Ecore_Promise*)promise); > > + return v; > > +} > > + > > +void ecore_promise_value_set(Ecore_Promise* promise, void* data) > > +{ > > + _ecore_promise_lock_take(promise); > > + if(data && promise->value_size) > > + { > > + memcpy(&promise->value[0], data, promise->value_size); > > + } > > + > > + _ecore_promise_finish(promise); > > +} > > + > > +static void _ecore_promise_all_compose_then_cb(Ecore_Promise* promise, > > void* value EINA_UNUSED) +{ > > + _ecore_promise_lock_take(promise); > > + _Ecore_Promise_Iterator* iterator = > > (_Ecore_Promise_Iterator*)promise->value; + > > + if(++iterator->data.data.promises_finished == > > iterator->data.data.num_promises) > > + { > > + _ecore_promise_finish(promise); > > + } > > + else > > + _ecore_promise_lock_release(promise); > > +} > > + > > +static void _ecore_promise_all_free(_Ecore_Promise_Iterator* value) > > +{ > > + unsigned i = 0; > > + eina_iterator_free(value->success_iterator); > > + /* eina_iterator_free(value->failure_iterator); */ > > + > > + for(;i != value->data.data.num_promises; ++i) > > + { > > + ecore_promise_unref(value->data.data.promises[i]); > > + } > > +} > > + > > +Ecore_Promise* ecore_promise_all(Eina_Iterator* it) > > +{ > > + Ecore_Promise* current, *promise; > > + Eina_Array* promises; > > + > > + promises = eina_array_new(20); > > + > > + EINA_ITERATOR_FOREACH(it, current) > > + { > > + eina_array_push(promises, current); > > + } > > + > > + promise = ecore_promise_add(sizeof(_Ecore_Promise_Iterator) + sizeof > > (Ecore_Promise*)*eina_array_count_get(promises)); > > + //promise->is_then_calls_manual = EINA_TRUE; > > + promise->free_cb = (Ecore_Promise_Free_Cb)_ecore_promise_all_free; > > + _Ecore_Promise_Iterator* internal_it = ecore_promise_buffer_get(promise); > > + _ecore_promise_iterator_setup(internal_it, promises); > > + eina_array_free(promises); > > + > > + { > > + Ecore_Promise** cur_promise = internal_it->data.data.promises, ** last > > = > > + internal_it->data.data.promises + > > internal_it->data.data.num_promises; > > + for(;cur_promise != last; ++cur_promise) > > + { > > + ecore_promise_ref(*cur_promise); > > + ecore_promise_then(*cur_promise, > > (Ecore_Promise_Cb)&_ecore_promise_all_compose_then_cb, promise); > > + } > > + } > > + > > + return promise; > > +} > > + > > +void ecore_promise_then(Ecore_Promise* promise, Ecore_Promise_Cb callback, > > void* data) +{ > > + _ecore_promise_lock_take(promise); > > + _ecore_promise_unsafe_ref(promise); > > + if(!promise->then_callbacks.callback && !EINA_INLIST_GET > > (&promise->then_callbacks)->next) > > + { > > + promise->then_callbacks.callback = callback; > > + promise->then_callbacks.data = data; > > + } > > + else > > + { > > + struct _Ecore_Promise_Then_Cb* p = malloc(sizeof(struct > > _Ecore_Promise_Then_Cb)); > > + p->callback = callback; > > + p->data = data; > > + Eina_Inlist* l = eina_inlist_append(EINA_INLIST_GET > > (&promise->then_callbacks), EINA_INLIST_GET(p)); > > + (void)l; > > + } > > + if(promise->has_finished && !promise->has_pending_call) > > + { > > + promise->has_pending_call = EINA_TRUE; > > + _ecore_promise_lock_release(promise); > > + ecore_job_add((Ecore_Cb)&_ecore_promise_then_calls, promise); > > + } > > + else > > + _ecore_promise_lock_release(promise); > > +} > > + > > +EAPI Eina_Error ecore_promise_error_get(Ecore_Promise const* promise) > > +{ > > + _ecore_promise_lock_take((Ecore_Promise*)promise); > > + if(promise->has_errored) > > + { > > + Eina_Error error = promise->error; > > + _ecore_promise_lock_release((Ecore_Promise*)promise); > > + return error; > > + } > > + else > > + { > > + _ecore_promise_lock_release((Ecore_Promise*)promise); > > + return 0; > > + } > > +} > > + > > +EAPI void ecore_promise_error_set(Ecore_Promise* promise, Eina_Error error) > > +{ > > + _ecore_promise_lock_take(promise); > > + promise->error = error; > > + promise->has_errored = EINA_TRUE; > > + > > + _ecore_promise_finish(promise); > > +} > > + > > +static void > > +_ecore_promise_finish(Ecore_Promise* promise) > > +{ > > + promise->has_finished = EINA_TRUE; > > + eina_condition_broadcast(&promise->condition); > > + _ecore_promise_unsafe_unref(promise); > > + if(!promise->is_then_calls_manual && !promise->has_pending_call) > > + { > > + promise->has_pending_call = EINA_TRUE; > > + _ecore_promise_lock_release(promise); > > + ecore_job_add((Ecore_Cb)&_ecore_promise_then_calls, promise); > > + } > > + else > > + _ecore_promise_lock_release(promise); > > +} > > + > > +static Eina_Bool > > +_ecore_promise_iterator_next(_Ecore_Promise_Success_Iterator *it, void > > **data) +{ > > + if(it->data.promise_index == it->data.num_promises) > > + return EINA_FALSE; > > + > > + if(ecore_promise_error_get(it->data.promises[it->data.promise_index])) > > + { > > + return EINA_FALSE; > > + } > > + else > > + { > > + *data = ecore_promise_value_get(it->data.promises > > [it->data.promise_index++]); > > + return EINA_TRUE; > > + } > > +} > > + > > +static void** > > +_ecore_promise_iterator_get_container(_Ecore_Promise_Success_Iterator *it) > > +{ > > + return (void**)it->data.promises; > > +} > > + > > +static void > > +_ecore_promise_iterator_free(_Ecore_Promise_Success_Iterator *it > > EINA_UNUSED) +{ > > +} > > + > > +static void _ecore_promise_iterator_setup(_Ecore_Promise_Iterator* it, > > Eina_Array* promises_array) +{ > > + Ecore_Promise** promises; > > + > > + it->success_iterator = &it->data.success_iterator_impl; > > + it->failure_iterator = &it->data.data.failure_iterator_impl; > > + it->data.data.num_promises = eina_array_count_get(promises_array); > > + it->data.data.promise_index = 0; > > + promises = (Ecore_Promise**)promises_array->data; > > + > > + memcpy(&it->data.data.promises[0], promises, > > it->data.data.num_promises*sizeof(Ecore_Promise*)); + > > + EINA_MAGIC_SET(&it->data.success_iterator_impl, EINA_MAGIC_ITERATOR); > > + EINA_MAGIC_SET(&it->data.data.failure_iterator_impl, > > EINA_MAGIC_ITERATOR); + > > + it->data.success_iterator_impl.version = EINA_ITERATOR_VERSION; > > + it->data.success_iterator_impl.next = FUNC_ITERATOR_NEXT > > (_ecore_promise_iterator_next); > > + it->data.success_iterator_impl.get_container = > > FUNC_ITERATOR_GET_CONTAINER( > > + _ecore_promise_iterator_get_container); > > + it->data.success_iterator_impl.free = FUNC_ITERATOR_FREE > > (_ecore_promise_iterator_free); +} > > + > > +EAPI int ecore_promise_value_size_get(Ecore_Promise const* promise) > > +{ > > + return promise->value_size; > > +} > > + > > +static void _ecore_promise_lock_take(Ecore_Promise* promise) > > +{ > > + eina_lock_take(&promise->lock); > > +} > > + > > +static void _ecore_promise_lock_release(Ecore_Promise* promise) > > +{ > > + eina_lock_release(&promise->lock); > > +} > > + > > +static void _ecore_promise_unsafe_ref(Ecore_Promise const* promise) > > +{ > > + Ecore_Promise* p = (Ecore_Promise*)promise; > > + ++p->ref; > > +} > > + > > +static void _ecore_promise_free_cb(Ecore_Promise* promise) > > +{ > > + _ecore_promise_lock_take(promise); > > + _ecore_promise_unlock_unsafe_free_unref(promise); > > +} > > + > > +static void _ecore_promise_unsafe_unref(Ecore_Promise const* promise) > > +{ > > + Ecore_Promise* p = (Ecore_Promise*)promise; > > + if(p->ref == 1 && !p->has_pending_call) > > + { > > + ecore_job_add((Ecore_Cb)_ecore_promise_free_cb, p); > > + } > > + else > > + --p->ref; > > +} > > + > > +static void _ecore_promise_unsafe_free_unref(Ecore_Promise const* promise) > > +{ > > + Ecore_Promise* p = (Ecore_Promise*)promise; > > + if(--p->ref == 0) > > + { > > + assert(!p->has_pending_call); > > + _ecore_promise_del(p); > > + } > > +} > > + > > +static Eina_Bool _ecore_promise_unlock_unsafe_free_unref(Ecore_Promise > > const* promise) +{ > > + Ecore_Promise* p = (Ecore_Promise*)promise; > > + if(--p->ref == 0) > > + { > > + assert(!p->has_pending_call); > > + _ecore_promise_lock_release((Ecore_Promise*)promise); > > + _ecore_promise_del(p); > > + return EINA_TRUE; > > + } > > + else > > + { > > + _ecore_promise_lock_release((Ecore_Promise*)promise); > > + return EINA_FALSE; > > + } > > +} > > + > > +EAPI void ecore_promise_ref(Ecore_Promise* promise) > > +{ > > + _ecore_promise_lock_take(promise); > > + _ecore_promise_unsafe_ref(promise); > > + _ecore_promise_lock_release(promise); > > +} > > + > > +EAPI void ecore_promise_unref(Ecore_Promise* promise) > > +{ > > + _ecore_promise_lock_take(promise); > > + _ecore_promise_unsafe_unref(promise); > > + _ecore_promise_lock_release(promise); > > +} > > diff --git a/src/lib/ecore/ecore_promise.h b/src/lib/ecore/ecore_promise.h > > new file mode 100644 > > index 0000000..834c336 > > --- /dev/null > > +++ b/src/lib/ecore/ecore_promise.h > > @@ -0,0 +1,136 @@ > > + > > +#ifdef EFL_BETA_API_SUPPORT > > + > > +struct _Ecore_Promise; > > + > > +/* > > + * @def _Ecore_Promise > > + */ > > +typedef struct _Ecore_Promise Ecore_Promise; > > + > > +/* > > + * @brief Function callback type for when using ecore_promise_then > > + */ > > +typedef void(*Ecore_Promise_Cb)(void* data, void* value); > > + > > +/* > > + * @brief Function callback type for when creating Ecore_Thread that > > + * uses Ecore_Promise for communication > > + */ > > +typedef void(*Ecore_Promise_Thread_Cb)(const void* data, Ecore_Promise* > > promise); + > > +/* > > + * @brief Function that instantiates a Ecore_Promise and automatically > > + * executes func_blocking callback function in another thread > > + */ > > +EAPI Ecore_Promise* ecore_promise_thread_run(Ecore_Promise_Thread_Cb > > func_blocking, const void* data, size_t value_size); + > > +/* > > + * @brief Creates a Ecore_Promise with a value of size value_size. > > + * > > + * @param value_size Size of value-type that Ecore_Promise will hold > > + */ > > +EAPI Ecore_Promise* ecore_promise_add(int value_size); > > + > > +/* > > + * @brief Appends a callback to be called when the Ecore_Promise is > > + * finished. > > + * > > + * @param promise The Ecore_Promise to wait for > > + * @param callback Callback to be called when Ecore_Promise is finished > > + * @param data Private data passed to the callback > > + */ > > +EAPI void ecore_promise_then(Ecore_Promise* promise, Ecore_Promise_Cb > > callback, void* data); + > > +/* > > + * @brief Creates a new Ecore_Promise from other Ecore_Promises > > + * > > + * @param promises An Eina_Iterator for all Ecore_Promises > > + */ > > +EAPI Ecore_Promise* ecore_promise_all(Eina_Iterator* promises); > > + > > +/* > > + * @brief Sets value for Ecore_Promise. This finishes the callback and > > + * calls all ecore_promise_then callbacks that have been registered on > > + * this Ecore_Promise. This function must be called only once per > > + * Ecore_Promise > > + * > > + * @param promise The promise for which to set the value > > + * @param value The pointer to the value that is going to be copied, or > > NULL. > > + */ > > +EAPI void ecore_promise_value_set(Ecore_Promise* promise, void* value); > > + > > +/* > > + * @brief Returns the pointer to the value if the Ecore_Promise is > > + * finished. Waits for it to be finished, otherwise. > > + * > > + * @param promise The promise for which to get the value > > + */ > > +EAPI void* ecore_promise_value_get(Ecore_Promise const* promise); > > + > > +/* > > + * @brief Returns the pointer to the buffer that holds the value. This > > + * function is useful to instantiate the value directly in the correct > > + * buffer, without needing to copy. The ecore_promise_value_set must > > + * still be called, possibly with NULL, to finish the Ecore_Promise > > + * and call the callbacks registered in it. > > + * > > + * @param promise The promise for which to get the buffer pointer > > + */ > > +EAPI void* ecore_promise_buffer_get(Ecore_Promise* promise); > > + > > +/* > > + * @brief Sets an error to the Ecore_Promise, thus finishing the > > + * promise and calling all ecore_promise_then callbacks registered. > > + * > > + * @param promise The promise for which to set the error > > + * @param error Eina_Error to be set > > + */ > > +EAPI void ecore_promise_error_set(Ecore_Promise* promise, Eina_Error > > error); + > > +/* > > + * @brief Gets an error to the Ecore_Promise if the promise is > > + * finished and has error'ed out. If it hasn't finished, it will wait, > > + * and if it has finished but otherwise not error'ed, returns 0. > > + * > > + * @param promise The promise for which to get the error > > + */ > > +EAPI Eina_Error ecore_promise_error_get(Ecore_Promise const* promise); > > + > > +/* > > + * @brief Gets the size of the value in ecore_promise_value_get. > > + * > > + * @param promise The promise for which to get the value size > > + */ > > +EAPI int ecore_promise_value_size_get(Ecore_Promise const* promise); > > + > > +/* > > + * @brief Returns @EINA_TRUE if the promise is ready and won't block > > + * on ecore_promise_value_get and @EINA_FALSE otherwise. > > + * > > + * @param promise The promise for which to get the ready status > > + */ > > +EAPI Eina_Bool ecore_promise_ready_is(Ecore_Promise const* promise); > > + > > +/* > > + * @brief Increments the reference count for the Ecore_Promise > > + * > > + * @param promise The promise for which to increment its reference > > + */ > > +EAPI void ecore_promise_ref(Ecore_Promise* promise); > > + > > +/* > > + * @brief Decrement the reference count for the Ecore_Promise and > > + * possibly schedule its destruction. The Ecore_Promise, if its > > + * reference count drops to zero, will only be free'd when all the > > + * current mainloop events have been processed. This allows the user > > + * to call ecore_promise_then before that happens so it can increment > > + * the reference back to 1 and wait for a value set or error set on > > + * the Ecore_Promise. > > + * > > + * @param promise The promise for which to decrement its reference > > + */ > > +EAPI void ecore_promise_unref(Ecore_Promise* promise); > > + > > +#endif > > + > > diff --git a/src/lib/eo/Eo.h b/src/lib/eo/Eo.h > > index ab920ee..936c8c8 100644 > > --- a/src/lib/eo/Eo.h > > +++ b/src/lib/eo/Eo.h > > @@ -511,61 +511,96 @@ typedef struct _Eo_Call_Cache > > __FILE__, __LINE__)) return DefRet; \ > > _Eo_##Name##_func _func_ = (_Eo_##Name##_func) ___call.func; \ > > > > +#define _EO_FUNC_PROMISE_CREATE0 > > +#define _EO_FUNC_PROMISE_FREE0 > > +#define _EO_FUNC_PROMISE_CREATE1 \ > > + Ecore_Promise*(*ecore_promise_add)(int size) = dlsym(dlopen(NULL, > > RTLD_NOW), "ecore_promise_add"); \ > > + Ecore_Promise* __eo_promise = ecore_promise_add(sizeof(PromiseValue)); > > +#define _EO_FUNC_PROMISE_FREE1 \ > > + if(Promise) \ > > + *Promise = __eo_promise; \ > > + else \ > > + { \ > > + void(*ecore_promise_unref)(Ecore_Promise* p) = dlsym(dlopen > > (NULL, RTLD_NOW), "ecore_promise_unref"); \ > > + ecore_promise_unref(__eo_promise); \ > > + } > > +#define _EO_EXPANSION_AUX(X) X > > +#define _EO_FUNC_PROMISE_CREATE(p) _EO_EXPANSION_AUX > > (_EO_FUNC_PROMISE_CREATE ## p) +#define _EO_FUNC_PROMISE_FREE(p) > > _EO_EXPANSION_AUX(_EO_FUNC_PROMISE_FREE ## p) + > > // to define an EAPI function > > -#define _EO_FUNC_BODY(Name, ObjType, Ret, > > DefRet) \ +#define _EO_FUNC_BODY(Name, > > ObjType, Promise, Ret, DefRet) \ > > Ret \ Name > > (ObjType obj) \ > > { \ > > typedef Ret (*_Eo_##Name##_func)(Eo *, void *obj_data); \ Ret > > _r; \ > > EO_FUNC_COMMON_OP(obj, Name, DefRet); \ > > + _EO_FUNC_PROMISE_CREATE(Promise) \ > > _r = _func_(___call.eo_id, ___call.data); > > \ _eo_call_end(&___call); \ > > + _EO_FUNC_PROMISE_FREE(Promise) \ > > return _r; \ > > } > > > > -#define _EO_VOID_FUNC_BODY(Name, > > ObjType) \ +#define > > _EO_VOID_FUNC_BODY(Name, ObjType, Promise) \ > > void > > \ Name(ObjType > > obj) \ > > { \ > > typedef void (*_Eo_##Name##_func)(Eo *, void *obj_data); \ > > EO_FUNC_COMMON_OP(obj, Name, ); \ > > + _EO_FUNC_PROMISE_CREATE(Promise) \ > > _func_(___call.eo_id, ___call.data); > > \ _eo_call_end(&___call); \ > > + _EO_FUNC_PROMISE_FREE(Promise) \ > > } > > > > -#define _EO_FUNC_BODYV(Name, ObjType, Ret, DefRet, > > Arguments, ...) \ +#define _EO_FUNC_BODYV(Name, ObjType, > > Promise, Ret, DefRet, Arguments, ...) \ > > Ret \ Name > > (ObjType obj, > > __VA_ARGS__) \ > > { \ > > typedef Ret (*_Eo_##Name##_func)(Eo *, void *obj_data, __VA_ARGS__); \ Ret > > _r; \ > > EO_FUNC_COMMON_OP(obj, Name, DefRet); \ > > + _EO_FUNC_PROMISE_CREATE(Promise) \ > > _r = _func_(___call.eo_id, ___call.data, Arguments); > > \ _eo_call_end(&___call); \ > > + _EO_FUNC_PROMISE_FREE(Promise) \ > > return _r; \ > > } > > > > -#define _EO_VOID_FUNC_BODYV(Name, ObjType, > > Arguments, ...) \ +#define _EO_VOID_FUNC_BODYV(Name, > > ObjType, Promise, Arguments, ...) \ > > void \ Name > > (ObjType obj, > > __VA_ARGS__) \ > > { \ > > typedef void (*_Eo_##Name##_func)(Eo *, void *obj_data, __VA_ARGS__); \ > > EO_FUNC_COMMON_OP(obj, Name, ); \ > > + _EO_FUNC_PROMISE_CREATE(Promise) \ > > _func_(___call.eo_id, ___call.data, Arguments); > > \ _eo_call_end(&___call); \ > > + _EO_FUNC_PROMISE_FREE(Promise) \ > > } > > > > -#define EO_FUNC_BODY(Name, Ret, DefRet) _EO_FUNC_BODY(Name, Eo *, Ret, > > DefRet) -#define EO_VOID_FUNC_BODY(Name) _EO_VOID_FUNC_BODY(Name, Eo *) > > -#define EO_FUNC_BODYV(Name, Ret, DefRet, Arguments, ...) _EO_FUNC_BODYV > > (Name, Eo *, Ret, DefRet, EO_FUNC_CALL(Arguments), __VA_ARGS__) -#define > > EO_VOID_FUNC_BODYV(Name, Arguments, ...) _EO_VOID_FUNC_BODYV(Name, Eo *, > > EO_FUNC_CALL(Arguments), __VA_ARGS__) - -#define EO_FUNC_BODY_CONST(Name, > > Ret, DefRet) _EO_FUNC_BODY(Name, const Eo *, Ret, DefRet) -#define > > EO_VOID_FUNC_BODY_CONST(Name) _EO_VOID_FUNC_BODY(Name, const Eo *) -#define > > EO_FUNC_BODYV_CONST(Name, Ret, DefRet, Arguments, ...) _EO_FUNC_BODYV(Name, > > const Eo *, Ret, DefRet, EO_FUNC_CALL(Arguments), __VA_ARGS__) -#define > > EO_VOID_FUNC_BODYV_CONST(Name, Arguments, ...) _EO_VOID_FUNC_BODYV(Name, > > const Eo *, EO_FUNC_CALL(Arguments), __VA_ARGS__) - +#define EO_FUNC_BODY > > (Name, Ret, DefRet) _EO_FUNC_BODY(Name, Eo *, 0, Ret, DefRet) +#define > > EO_VOID_FUNC_BODY(Name) _EO_VOID_FUNC_BODY(Name, Eo *, 0) +#define > > EO_FUNC_BODYV(Name, Ret, DefRet, Arguments, ...) _EO_FUNC_BODYV(Name, Eo *, > > 0, Ret, DefRet, EO_FUNC_CALL(Arguments), __VA_ARGS__) +#define > > EO_VOID_FUNC_BODYV(Name, Arguments, ...) _EO_VOID_FUNC_BODYV(Name, Eo *, 0, > > EO_FUNC_CALL(Arguments), __VA_ARGS__) + +#define EO_FUNC_BODY_CONST(Name, > > Ret, DefRet) _EO_FUNC_BODY(Name, const Eo *, 0, Ret, DefRet) +#define > > EO_VOID_FUNC_BODY_CONST(Name) _EO_VOID_FUNC_BODY(Name, const Eo *, 0) > > +#define EO_FUNC_BODYV_CONST(Name, Ret, DefRet, Arguments, ...) > > _EO_FUNC_BODYV(Name, const Eo *, 0, Ret, DefRet, EO_FUNC_CALL(Arguments), > > __VA_ARGS__) +#define EO_VOID_FUNC_BODYV_CONST(Name, Arguments, ...) > > _EO_VOID_FUNC_BODYV(Name, const Eo *, 0, EO_FUNC_CALL(Arguments), > > __VA_ARGS__) + +#define EO_FUNC_PROMISE_BODY(Name, Ret, DefRet) > > _EO_FUNC_BODY(Name, Eo *, 1, Ret, DefRet) +#define EO_VOID_FUNC_PROMISE_BODY > > (Name) _EO_VOID_FUNC_BODY(Name, Eo *, 1) +#define EO_FUNC_PROMISE_BODYV > > (Name, Ret, DefRet, Arguments, ...) _EO_FUNC_BODYV(Name, Eo *, 1, Ret, > > DefRet, EO_FUNC_CALL(Arguments), __VA_ARGS__) +#define > > EO_VOID_FUNC_PROMISE_BODYV(Name, Arguments, ...) _EO_VOID_FUNC_BODYV(Name, > > Eo *, 1, EO_FUNC_CALL(Arguments), __VA_ARGS__) + +#define > > EO_FUNC_PROMISE_BODY_CONST(Name, Ret, DefRet) _EO_FUNC_BODY(Name, const Eo > > *, 1, Ret, DefRet) +#define EO_VOID_FUNC_PROMISE_BODY_CONST(Name) > > _EO_VOID_FUNC_BODY(Name, const Eo *, 1) +#define EO_FUNC_PROMISE_BODYV_CONST > > (Name, Ret, DefRet, Arguments, ...) _EO_FUNC_BODYV(Name, const Eo *, 1, > > Ret, DefRet, EO_FUNC_CALL(Arguments), __VA_ARGS__) +#define > > EO_VOID_FUNC_PROMISE_BODYV_CONST(Name, Arguments, ...) _EO_VOID_FUNC_BODYV > > (Name, const Eo *, 1, EO_FUNC_CALL(Arguments), __VA_ARGS__) + > > #ifndef _WIN32 > > # define _EO_OP_API_ENTRY(a) (void*)a > > #else > > diff --git a/src/lib/eolian/eo_lexer.c b/src/lib/eolian/eo_lexer.c > > index 0e98313..1aeb6a9 100644 > > --- a/src/lib/eolian/eo_lexer.c > > +++ b/src/lib/eolian/eo_lexer.c > > @@ -75,7 +75,8 @@ static const char * const ctypes[] = > > "Eina_Accessor", "Eina_Array", "Eina_Iterator", "Eina_Hash", > > "Eina_List", "Eina_Value", > > > > - "Eo_Event_Cb" > > + "Eo_Event_Cb", > > + "Ecore_Promise" > > }; > > > > #undef KW > > diff --git a/src/lib/eolian/eo_lexer.h b/src/lib/eolian/eo_lexer.h > > index b28a3fc..bb4385b 100644 > > --- a/src/lib/eolian/eo_lexer.h > > +++ b/src/lib/eolian/eo_lexer.h > > @@ -52,7 +52,9 @@ enum Tokens > > \ > > KW(accessor), KW(array), KW(iterator), KW(hash), KW(list), KW > > (generic_value), \ \ > > - KW(__builtin_event_cb), KW(__undefined_type), \ > > + KW(__builtin_event_cb), \ > > + KW(Promise), \ > > + KW(__undefined_type), \ > > \ > > KW(true), KW(false), KW(null) > > > > @@ -206,4 +208,4 @@ void eo_lexer_context_pop (Eo_Lexer *ls); > > void eo_lexer_context_restore(Eo_Lexer *ls); > > void eo_lexer_context_clear (Eo_Lexer *ls); > > > > -#endif /* __EO_LEXER_H__ */ > > \ No newline at end of file > > +#endif /* __EO_LEXER_H__ */ > > diff --git a/src/lib/eolian/eo_parser.c b/src/lib/eolian/eo_parser.c > > index 6b6df14..a0d9ddd 100644 > > --- a/src/lib/eolian/eo_parser.c > > +++ b/src/lib/eolian/eo_parser.c > > @@ -782,7 +782,7 @@ parse_type_void_base(Eo_Lexer *ls, Eina_Bool noptr) > > _fill_name(eina_stringshare_ref(ls->t.value.s), > > &def->full_name, &def->name, &def->namespaces); > > eo_lexer_get(ls); > > - if (tpid >= KW_accessor && tpid <= KW_list) > > + if ((tpid >= KW_accessor && tpid <= KW_list) || tpid == > > KW_Promise) { > > int bline = ls->line_number, bcol = ls->column; > > def->type = EOLIAN_TYPE_COMPLEX; > > diff --git a/src/tests/ecore/ecore_suite.c b/src/tests/ecore/ecore_suite.c > > index 787a455..04ad191 100644 > > --- a/src/tests/ecore/ecore_suite.c > > +++ b/src/tests/ecore/ecore_suite.c > > @@ -26,6 +26,7 @@ static const Efl_Test_Case etc[] = { > > #endif > > { "Ecore_Input", ecore_test_ecore_input }, > > { "Ecore_File", ecore_test_ecore_file }, > > + { "Ecore_Promise", ecore_test_ecore_promise }, > > { NULL, NULL } > > }; > > > > diff --git a/src/tests/ecore/ecore_suite.h b/src/tests/ecore/ecore_suite.h > > index f0e4c2a..558e610 100644 > > --- a/src/tests/ecore/ecore_suite.h > > +++ b/src/tests/ecore/ecore_suite.h > > @@ -15,5 +15,6 @@ void ecore_test_ecore_drm(TCase *tc); > > void ecore_test_ecore_fb(TCase *tc); > > void ecore_test_ecore_input(TCase *tc); > > void ecore_test_ecore_file(TCase *tc); > > +void ecore_test_ecore_promise(TCase *tc); > > > > #endif /* _ECORE_SUITE_H */ > > diff --git a/src/tests/ecore/ecore_test_promise.c > > b/src/tests/ecore/ecore_test_promise.c new file mode 100644 > > index 0000000..0f003fd > > --- /dev/null > > +++ b/src/tests/ecore/ecore_test_promise.c > > @@ -0,0 +1,364 @@ > > +#ifdef HAVE_CONFIG_H > > +# include <config.h> > > +#endif > > + > > +#include <Ecore.h> > > +#include "ecore_suite.h" > > +#include <time.h> > > + > > +void promised_thread(const void* data EINA_UNUSED, Ecore_Promise* promise) > > +{ > > + fprintf(stderr, "%s:%d %s\n", __FILE__, __LINE__, __func__); fflush > > (stderr); > > + ecore_promise_value_set(promise, NULL); > > +} > > + > > +void promise_callback(void* data EINA_UNUSED, void* value EINA_UNUSED) > > +{ > > + fprintf(stderr, "%s:%d %s\n", __FILE__, __LINE__, __func__); fflush > > (stderr); > > + ecore_main_loop_quit(); > > +} > > + > > +START_TEST(ecore_test_promise) > > +{ > > + ecore_init(); > > + fprintf(stderr, "%s:%d %s ---------- BEGIN test\n", __FILE__, __LINE__, > > __func__); fflush(stderr); + > > + fprintf(stderr, "%s:%d %s\n", __FILE__, __LINE__, __func__); fflush > > (stderr); > > + Ecore_Promise* promise = ecore_promise_thread_run(&promised_thread, > > NULL, 0); > > + ecore_promise_then(promise, &promise_callback, NULL); > > + fprintf(stderr, "%s:%d %s\n", __FILE__, __LINE__, __func__); fflush > > (stderr); + > > + ecore_main_loop_begin(); > > + > > + fprintf(stderr, "%s:%d %s ---------- END test\n", __FILE__, __LINE__, > > __func__); fflush(stderr); > > + ecore_shutdown(); > > +} > > +END_TEST > > + > > +void promise_error_thread(const void* data EINA_UNUSED, Ecore_Promise* > > promise) +{ > > + fprintf(stderr, "%s:%d %s\n", __FILE__, __LINE__, __func__); fflush > > (stderr); > > + ecore_promise_error_set(promise, EINA_ERROR_OUT_OF_MEMORY); > > +} > > + > > +void promise_error_callback(void* data EINA_UNUSED, void* value > > EINA_UNUSED) +{ > > + fprintf(stderr, "%s:%d %s\n", __FILE__, __LINE__, __func__); fflush > > (stderr); > > + ecore_main_loop_quit(); > > +} > > + > > +START_TEST(ecore_test_promise_error) > > +{ > > + ecore_init(); > > + fprintf(stderr, "%s:%d %s ---------- BEGIN test\n", __FILE__, __LINE__, > > __func__); fflush(stderr); + > > + fprintf(stderr, "%s:%d %s\n", __FILE__, __LINE__, __func__); fflush > > (stderr); > > + Ecore_Promise* promise = ecore_promise_thread_run > > (&promise_error_thread, NULL, 0); > > + ecore_promise_then(promise, &promise_error_callback, NULL); > > + fprintf(stderr, "%s:%d %s\n", __FILE__, __LINE__, __func__); fflush > > (stderr); + > > + ecore_main_loop_begin(); > > + > > + fprintf(stderr, "%s:%d %s ---------- END test\n", __FILE__, __LINE__, > > __func__); fflush(stderr); > > + ecore_shutdown(); > > +} > > +END_TEST > > + > > +START_TEST(ecore_test_promise_all) > > +{ > > + ecore_init(); > > + fprintf(stderr, "%s:%d %s ---------- BEGIN test\n", __FILE__, __LINE__, > > __func__); fflush(stderr); + > > + fprintf(stderr, "%s:%d %s\n", __FILE__, __LINE__, __func__); fflush > > (stderr); > > + Ecore_Promise* first[2] = { ecore_promise_thread_run(&promised_thread, > > NULL, 0), NULL }; > > + Ecore_Promise* promise = ecore_promise_all(eina_carray_iterator_new > > ((void**)&first[0])); > > + ecore_promise_then(promise, &promise_callback, NULL); > > + fprintf(stderr, "%s:%d %s\n", __FILE__, __LINE__, __func__); fflush > > (stderr); + > > + ecore_main_loop_begin(); > > + > > + fprintf(stderr, "%s:%d %s ---------- END test\n", __FILE__, __LINE__, > > __func__); fflush(stderr); > > + ecore_shutdown(); > > +} > > +END_TEST > > + > > +void promise_callback2(void* data, void* value EINA_UNUSED) > > +{ > > + fprintf(stderr, "%s:%d %s\n", __FILE__, __LINE__, __func__); fflush > > (stderr); > > + if(++(*(int*)data) == 2) > > + ecore_main_loop_quit(); > > +} > > + > > +START_TEST(ecore_test_promise_all_then_then) > > +{ > > + ecore_init(); > > + fprintf(stderr, "%s:%d %s ---------- BEGIN test\n", __FILE__, __LINE__, > > __func__); fflush(stderr); + > > + int i = 0; > > + > > + fprintf(stderr, "%s:%d %s\n", __FILE__, __LINE__, __func__); fflush > > (stderr); > > + Ecore_Promise* first[2] = { ecore_promise_thread_run(&promised_thread, > > NULL, 0), NULL }; > > + ecore_promise_then(first[0], &promise_callback2, &i); > > + Ecore_Promise* promise = ecore_promise_all(eina_carray_iterator_new > > ((void**)&first[0])); > > + ecore_promise_then(promise, &promise_callback2, &i); > > + fprintf(stderr, "%s:%d %s\n", __FILE__, __LINE__, __func__); fflush > > (stderr); + > > + ecore_main_loop_begin(); > > + > > + fprintf(stderr, "%s:%d %s ---------- END test\n", __FILE__, __LINE__, > > __func__); fflush(stderr); > > + ecore_shutdown(); > > +} > > +END_TEST > > + > > +struct sync_data > > +{ > > + Eina_Lock lock; > > + Eina_Condition cond; > > + Eina_Bool var; > > +}; > > + > > +void promised_exit_thread(struct sync_data* data EINA_UNUSED, > > Ecore_Promise* promise) +{ > > + fprintf(stderr, "%s:%d %s\n", __FILE__, __LINE__, __func__); fflush > > (stderr); > > + ecore_promise_value_set(promise, NULL); > > + eina_lock_take(&data->lock); > > + data->var = EINA_TRUE; > > + eina_condition_broadcast(&data->cond); > > + eina_lock_release(&data->lock); > > +} > > + > > +static void _ecore_test_promise_then_after_thread_finished_main_cb() > > +{ > > + struct sync_data data; > > + data.var = EINA_FALSE; > > + eina_lock_new(&data.lock); > > + eina_condition_new(&data.cond, &data.lock); > > + > > + Ecore_Promise* promise = ecore_promise_thread_run > > ((Ecore_Promise_Thread_Cb)&promised_exit_thread, &data, 0); + > > + eina_lock_take(&data.lock); > > + while(!data.var) > > + { > > + eina_condition_wait(&data.cond); > > + } > > + eina_lock_release(&data.lock); > > + ecore_promise_then(promise, &promise_callback, NULL); > > +} > > + > > +START_TEST(ecore_test_promise_then_after_thread_finished) > > +{ > > + ecore_init(); > > + fprintf(stderr, "%s:%d %s ---------- BEGIN test\n", __FILE__, __LINE__, > > __func__); fflush(stderr); + > > + ecore_job_add(&_ecore_test_promise_then_after_thread_finished_main_cb, > > NULL); > > + ecore_main_loop_begin(); > > + > > + fprintf(stderr, "%s:%d %s ---------- END test\n", __FILE__, __LINE__, > > __func__); fflush(stderr); > > + ecore_shutdown(); > > +} > > +END_TEST > > + > > +static void _ecore_test_promise_then_after_thread_finished_all_main_cb() > > +{ > > + struct sync_data data; > > + data.var = EINA_FALSE; > > + eina_lock_new(&data.lock); > > + eina_condition_new(&data.cond, &data.lock); > > + > > + Ecore_Promise* first[] = {ecore_promise_thread_run > > ((Ecore_Promise_Thread_Cb)&promised_exit_thread, &data, 0), NULL}; > > + Ecore_Promise* promise = ecore_promise_all(eina_carray_iterator_new > > ((void**)&first[0])); + > > + eina_lock_take(&data.lock); > > + while(!data.var) > > + { > > + eina_condition_wait(&data.cond); > > + } > > + eina_lock_release(&data.lock); > > + ecore_promise_then(promise, &promise_callback, NULL); > > +} > > + > > +START_TEST(ecore_test_promise_then_after_thread_finished_all) > > +{ > > + ecore_init(); > > + fprintf(stderr, "%s:%d %s ---------- BEGIN test\n", __FILE__, __LINE__, > > __func__); fflush(stderr); + > > + ecore_job_add > > (&_ecore_test_promise_then_after_thread_finished_all_main_cb, NULL); > > + ecore_main_loop_begin(); > > + > > + fprintf(stderr, "%s:%d %s ---------- END test\n", __FILE__, __LINE__, > > __func__); fflush(stderr); > > + ecore_shutdown(); > > +} > > +END_TEST > > + > > +void promised_block_thread(const void* data EINA_UNUSED, Ecore_Promise* > > promise) +{ > > + struct timespec v = {.tv_sec = 1, .tv_nsec = 0}, rem; > > + if(nanosleep(&v, &rem) == -1 && errno == EINTR) > > + do > > + { > > + v = rem; > > + } > > + while(nanosleep(&v, &rem) == -1 && errno == EINTR); > > + > > + int r = 10; > > + ecore_promise_value_set(promise, &r); > > +} > > + > > +static void > > +_ecore_test_promise_blocking_get_quit_cb(void* data EINA_UNUSED) > > +{ > > + ecore_main_loop_quit(); > > +} > > + > > +static void > > +_ecore_test_promise_blocking_get_main_cb(void* data EINA_UNUSED) > > +{ > > + Ecore_Promise* promise = ecore_promise_thread_run > > (&promised_block_thread, NULL, sizeof(int)); > > + const void* value = ecore_promise_value_get(promise); > > + ck_assert(*(int*)value == 10); > > + > > + ecore_job_add(&_ecore_test_promise_blocking_get_quit_cb, NULL); > > +} > > + > > +START_TEST(ecore_test_promise_blocking_get) > > +{ > > + ecore_init(); > > + fprintf(stderr, "%s:%d %s ---------- BEGIN test\n", __FILE__, __LINE__, > > __func__); fflush(stderr); + > > + ecore_job_add(&_ecore_test_promise_blocking_get_main_cb, NULL); > > + ecore_main_loop_begin(); > > + > > + fprintf(stderr, "%s:%d %s ---------- END test\n", __FILE__, __LINE__, > > __func__); fflush(stderr); > > + ecore_shutdown(); > > +} > > +END_TEST > > + > > +static void > > +_ecore_test_promise_blocking_get_all_value_get_cb(Ecore_Promise* promise, > > Ecore_Thread* thread EINA_UNUSED) +{ > > + Eina_Iterator** iterator = ecore_promise_value_get(promise); > > + int* v; > > + ck_assert(eina_iterator_next(*iterator, (void**)&v)); > > + ck_assert(*v == 10); > > + ecore_main_loop_quit(); > > +} > > + > > +static void > > +_ecore_test_promise_blocking_get_all_main_cb(void* data EINA_UNUSED) > > +{ > > + Ecore_Promise* first[2] = {ecore_promise_thread_run > > (&promised_block_thread, NULL, sizeof(int)), NULL}; > > + Ecore_Promise* promise = ecore_promise_all(eina_carray_iterator_new > > ((void**)&first[0])); + > > + ecore_thread_run > > ((Ecore_Thread_Cb)&_ecore_test_promise_blocking_get_all_value_get_cb, NULL, > > NULL, promise); +} + > > +START_TEST(ecore_test_promise_blocking_get_all) > > +{ > > + ecore_init(); > > + fprintf(stderr, "%s:%d %s ---------- BEGIN test\n", __FILE__, __LINE__, > > __func__); fflush(stderr); + > > + ecore_job_add(&_ecore_test_promise_blocking_get_all_main_cb, NULL); > > + ecore_main_loop_begin(); > > + > > + fprintf(stderr, "%s:%d %s ---------- END test\n", __FILE__, __LINE__, > > __func__); fflush(stderr); > > + ecore_shutdown(); > > +} > > +END_TEST > > + > > +static void > > +_ecore_test_promise_normal_lifetime_cb(void* data EINA_UNUSED, void* value > > EINA_UNUSED) +{ > > + ecore_main_loop_quit(); > > +} > > + > > +START_TEST(ecore_test_promise_normal_lifetime) > > +{ > > + ecore_init(); > > + fprintf(stderr, "%s:%d %s ---------- BEGIN test\n", __FILE__, __LINE__, > > __func__); fflush(stderr); + > > + Ecore_Promise* promise = ecore_promise_add(0); > > + > > + ecore_promise_then(promise, &_ecore_test_promise_normal_lifetime_cb, > > NULL); > > + ecore_promise_value_set(promise, NULL); > > + > > + ecore_main_loop_begin(); > > + > > + fprintf(stderr, "%s:%d %s ---------- END test\n", __FILE__, __LINE__, > > __func__); fflush(stderr); > > + ecore_shutdown(); > > +} > > +END_TEST > > + > > +START_TEST(ecore_test_promise_normal_lifetime_all) > > +{ > > + ecore_init(); > > + fprintf(stderr, "%s:%d %s ---------- BEGIN test\n", __FILE__, __LINE__, > > __func__); fflush(stderr); + > > + Ecore_Promise* first[2] = {ecore_promise_add(0), NULL}; > > + Ecore_Promise* promise = ecore_promise_all(eina_carray_iterator_new > > ((void**)&first[0])); + > > + ecore_promise_then(promise, &_ecore_test_promise_normal_lifetime_cb, > > NULL); > > + ecore_promise_value_set(promise, NULL); > > + > > + ecore_main_loop_begin(); > > + > > + fprintf(stderr, "%s:%d %s ---------- END test\n", __FILE__, __LINE__, > > __func__); fflush(stderr); > > + ecore_shutdown(); > > +} > > +END_TEST > > + > > +static void > > +_ecore_test_promise_immediate_set_lifetime_cb(void* data EINA_UNUSED, > > void* value EINA_UNUSED) +{ > > + ecore_main_loop_quit(); > > +} > > + > > +START_TEST(ecore_test_promise_immediate_set_lifetime) > > +{ > > + ecore_init(); > > + fprintf(stderr, "%s:%d %s ---------- BEGIN test\n", __FILE__, __LINE__, > > __func__); fflush(stderr); + > > + Ecore_Promise* promise = ecore_promise_add(0); > > + > > + ecore_promise_value_set(promise, NULL); > > + ecore_promise_then(promise, > > &_ecore_test_promise_immediate_set_lifetime_cb, NULL); + > > + ecore_main_loop_begin(); > > + > > + fprintf(stderr, "%s:%d %s ---------- END test\n", __FILE__, __LINE__, > > __func__); fflush(stderr); > > + ecore_shutdown(); > > +} > > +END_TEST > > + > > +START_TEST(ecore_test_promise_immediate_set_lifetime_all) > > +{ > > + ecore_init(); > > + fprintf(stderr, "%s:%d %s ---------- BEGIN test\n", __FILE__, __LINE__, > > __func__); fflush(stderr); + > > + Ecore_Promise* first[2] = {ecore_promise_add(0), NULL}; > > + Ecore_Promise* promise = ecore_promise_all(eina_carray_iterator_new > > ((void**)&first[0])); + > > + ecore_promise_value_set(first[0], NULL); > > + ecore_promise_then(promise, > > &_ecore_test_promise_immediate_set_lifetime_cb, NULL); + > > + ecore_main_loop_begin(); > > + > > + fprintf(stderr, "%s:%d %s ---------- END test\n", __FILE__, __LINE__, > > __func__); fflush(stderr); > > + ecore_shutdown(); > > +} > > +END_TEST > > + > > +void ecore_test_ecore_promise(TCase *tc EINA_UNUSED) > > +{ > > + tcase_add_test(tc, ecore_test_promise); > > + tcase_add_test(tc, ecore_test_promise_error); > > + tcase_add_test(tc, ecore_test_promise_all); > > + tcase_add_test(tc, ecore_test_promise_all_then_then); > > + tcase_add_test(tc, ecore_test_promise_then_after_thread_finished); > > + tcase_add_test(tc, ecore_test_promise_then_after_thread_finished_all); > > + tcase_add_test(tc, ecore_test_promise_blocking_get); > > + tcase_add_test(tc, ecore_test_promise_blocking_get_all); > > + tcase_add_test(tc, ecore_test_promise_normal_lifetime); > > + tcase_add_test(tc, ecore_test_promise_normal_lifetime_all); > > + tcase_add_test(tc, ecore_test_promise_immediate_set_lifetime); > > + tcase_add_test(tc, ecore_test_promise_immediate_set_lifetime_all); > > +} > > > > > ------------------------------------------------------------------------------ > Transform Data into Opportunity. > Accelerate data analysis in your applications with > Intel Data Analytics Acceleration Library. > Click to learn more. > http://makebettercode.com/inteldaal-eval > _______________________________________________ > enlightenment-devel mailing list > enlightenment-devel@lists.sourceforge.net > https://lists.sourceforge.net/lists/listinfo/enlightenment-devel > -- ------------- Codito, ergo sum - "I code, therefore I am" -------------- The Rasterman (Carsten Haitzler) ras...@rasterman.com ------------------------------------------------------------------------------ Transform Data into Opportunity. Accelerate data analysis in your applications with Intel Data Analytics Acceleration Library. Click to learn more. http://pubads.g.doubleclick.net/gampad/clk?id=278785111&iu=/4140 _______________________________________________ enlightenment-devel mailing list enlightenment-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/enlightenment-devel