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

Reply via email to