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);
+}

-- 


Reply via email to