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.

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.

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

Reply via email to