eina: Fix memory leaks in promise
authorFelipe Magno de Almeida <felipe@expertisesolutions.com.br>
Fri, 6 May 2016 19:32:10 +0000 (16:32 -0300)
committerFelipe Magno de Almeida <felipe@expertisesolutions.com.br>
Sat, 7 May 2016 16:55:18 +0000 (13:55 -0300)
src/lib/ecore/ecore_thread_promise.c
src/lib/eina/eina_main.c
src/lib/eina/eina_promise.c
src/lib/eina/eina_promise.h
src/tests/ecore/ecore_test_promise.c
src/tests/eina/eina_test_promise.c

index dbc3ce9..1dea1bc 100644 (file)
@@ -7,6 +7,8 @@
 
 #include <assert.h>
 
+#include <ecore_private.h>
+
 struct _Ecore_Thread_Data
 {
    Ecore_Thread_Promise_Cb func_blocking;
@@ -20,10 +22,38 @@ struct _Ecore_Thread_Promise_Owner
 {
    Eina_Promise_Owner owner_vtable;
    Eina_Promise_Owner* eina_owner;
+   Eina_Promise promise_vtable;
+   Eina_Promise* eina_promise;
    _Ecore_Thread_Data thread_callback_data;
+   int ref_count;
+   int then_count;
 };
 typedef struct  _Ecore_Thread_Promise_Owner _Ecore_Thread_Promise_Owner;
 
+#define ECORE_PROMISE_GET_OWNER(p) (_Ecore_Thread_Promise_Owner*)((unsigned char*)p - offsetof(struct _Ecore_Thread_Promise_Owner, promise_vtable))
+
+static void _ecore_promise_ref_update(_Ecore_Thread_Promise_Owner* p)
+{
+  if(p->ref_count < 0)
+    {
+       ERR("Reference count is negative for promise %p\n", p);
+    }
+  if(!p->ref_count)
+    {
+       p->eina_promise->unref(p->eina_promise);
+       p->eina_promise = NULL;
+       p->eina_owner = NULL;
+       p->thread_callback_data.thread = NULL;
+    }
+}
+
+static void _ecore_promise_thread_release_ref(void* data, void* value EINA_UNUSED)
+{
+   _Ecore_Thread_Promise_Owner* p = data;
+   p->ref_count -= p->then_count;
+   _ecore_promise_ref_update(p);
+}
+
 static void _ecore_promise_thread_end(void* data, Ecore_Thread* thread EINA_UNUSED)
 {
    _Ecore_Thread_Promise_Owner* p = data;
@@ -31,10 +61,14 @@ static void _ecore_promise_thread_end(void* data, Ecore_Thread* thread EINA_UNUS
      {
         eina_promise_owner_default_manual_then_set(p->eina_owner, EINA_FALSE);
         eina_promise_owner_default_call_then(p->eina_owner);
+        p->ref_count -= p->then_count;
+        _ecore_promise_ref_update(p);
      }
    else
      {
         eina_promise_owner_default_manual_then_set(p->eina_owner, EINA_FALSE);
+        eina_promise_then(p->eina_promise, &_ecore_promise_thread_release_ref,
+                          (Eina_Promise_Error_Cb)&_ecore_promise_thread_release_ref, p);
      }
 }
 
@@ -51,7 +85,7 @@ static void _ecore_promise_thread_notify(void* data, Ecore_Thread* thread EINA_U
    eina_promise_owner_progress(promise->eina_owner, msg_data);
 }
 
-static void _ecore_promise_cancel(void* data, Eina_Promise_Owner* promise EINA_UNUSED)
+static void _ecore_promise_cancel_cb(void* data, Eina_Promise_Owner* promise EINA_UNUSED)
 {
    _Ecore_Thread_Promise_Owner* priv = data;
    (priv->thread_callback_data.func_cancel)(priv->thread_callback_data.data, &priv->owner_vtable,
@@ -93,12 +127,76 @@ static Eina_Bool _ecore_promise_owner_cancelled_is(_Ecore_Thread_Promise_Owner c
 }
 static Eina_Promise* _ecore_thread_promise_owner_promise_get(_Ecore_Thread_Promise_Owner* promise)
 {
-   return promise->eina_owner->promise_get(promise->eina_owner);
+   return &promise->promise_vtable;
 }
 static void _ecore_thread_promise_owner_progress(_Ecore_Thread_Promise_Owner* promise, void* data)
 {
    ecore_thread_feedback(promise->thread_callback_data.thread, data);
 }
+static void _ecore_thread_promise_owner_progress_notify(_Ecore_Thread_Promise_Owner* promise,
+                                                        Eina_Promise_Progress_Notify_Cb progress_cb,
+                                                        void* data, Eina_Promise_Free_Cb free_cb)
+{
+   promise->eina_owner->progress_notify(promise->eina_owner, progress_cb, data, free_cb);
+}
+
+static void _ecore_promise_then(Eina_Promise* promise, Eina_Promise_Cb callback,
+                                Eina_Promise_Error_Cb error_cb, void* data)
+{
+   _Ecore_Thread_Promise_Owner* v = ECORE_PROMISE_GET_OWNER(promise);
+   v->eina_promise->then(v->eina_promise, callback, error_cb, data);
+   if(v->then_count)
+     {
+        v->ref_count++;
+     }
+   v->then_count++;
+}
+static void* _ecore_promise_value_get(Eina_Promise const* promise)
+{
+   _Ecore_Thread_Promise_Owner* v = ECORE_PROMISE_GET_OWNER(promise);
+   return v->eina_promise->value_get(v->eina_promise);
+}
+static Eina_Error _ecore_promise_error_get(Eina_Promise const* promise)
+{
+   _Ecore_Thread_Promise_Owner* v = ECORE_PROMISE_GET_OWNER(promise);
+   return v->eina_promise->error_get(v->eina_promise);
+}
+static Eina_Bool _ecore_promise_pending_is(Eina_Promise const* promise)
+{
+   _Ecore_Thread_Promise_Owner* v = ECORE_PROMISE_GET_OWNER(promise);
+   return v->eina_promise->pending_is(v->eina_promise);
+}
+static void _ecore_promise_progress_cb_add(Eina_Promise const* promise, Eina_Promise_Progress_Cb callback, void* data,
+                                           Eina_Promise_Free_Cb free_cb)
+{
+   _Ecore_Thread_Promise_Owner* v = ECORE_PROMISE_GET_OWNER(promise);
+   v->eina_promise->progress_cb_add(v->eina_promise, callback, data, free_cb);
+}
+static void _ecore_promise_cancel(Eina_Promise const* promise)
+{
+   _Ecore_Thread_Promise_Owner* v = ECORE_PROMISE_GET_OWNER(promise);
+   v->eina_promise->cancel(v->eina_promise);
+}
+static void _ecore_promise_ref(Eina_Promise const* promise)
+{
+   _Ecore_Thread_Promise_Owner* v = ECORE_PROMISE_GET_OWNER(promise);
+   ++v->ref_count;   
+}
+static void _ecore_promise_unref(Eina_Promise const* promise)
+{
+   _Ecore_Thread_Promise_Owner* v = ECORE_PROMISE_GET_OWNER(promise);
+   --v->ref_count;   
+}
+static void* _ecore_promise_buffer_get(Eina_Promise const* promise)
+{
+   _Ecore_Thread_Promise_Owner* v = ECORE_PROMISE_GET_OWNER(promise);
+   return v->eina_promise->buffer_get(v->eina_promise);
+}
+static size_t _ecore_promise_value_size_get(Eina_Promise const* promise)
+{
+   _Ecore_Thread_Promise_Owner* v = ECORE_PROMISE_GET_OWNER(promise);
+   return v->eina_promise->value_size_get(v->eina_promise);
+}
 
 Ecore_Thread* ecore_thread_promise_run(Ecore_Thread_Promise_Cb func_blocking,
                                        Ecore_Thread_Promise_Cb func_cancel,
@@ -120,18 +218,36 @@ Ecore_Thread* ecore_thread_promise_run(Ecore_Thread_Promise_Cb func_blocking,
    priv->owner_vtable.pending_is = EINA_FUNC_PROMISE_OWNER_PENDING_IS(&_ecore_promise_owner_pending_is);
    priv->owner_vtable.cancelled_is = EINA_FUNC_PROMISE_OWNER_CANCELLED_IS(&_ecore_promise_owner_cancelled_is);
    priv->owner_vtable.progress = EINA_FUNC_PROMISE_OWNER_PROGRESS(&_ecore_thread_promise_owner_progress);
-
+   priv->owner_vtable.progress_notify = EINA_FUNC_PROMISE_OWNER_PROGRESS_NOTIFY(&_ecore_thread_promise_owner_progress_notify);
+
+   priv->promise_vtable.then = EINA_FUNC_PROMISE_THEN(&_ecore_promise_then);
+   priv->promise_vtable.value_get = EINA_FUNC_PROMISE_VALUE_GET(&_ecore_promise_value_get);
+   priv->promise_vtable.error_get = EINA_FUNC_PROMISE_ERROR_GET(&_ecore_promise_error_get);
+   priv->promise_vtable.pending_is = EINA_FUNC_PROMISE_PENDING_IS(&_ecore_promise_pending_is);
+   priv->promise_vtable.progress_cb_add = EINA_FUNC_PROMISE_PROGRESS_CB_ADD(&_ecore_promise_progress_cb_add);
+   priv->promise_vtable.cancel = EINA_FUNC_PROMISE_CANCEL(&_ecore_promise_cancel);
+   priv->promise_vtable.ref = EINA_FUNC_PROMISE_REF(&_ecore_promise_ref);
+   priv->promise_vtable.unref = EINA_FUNC_PROMISE_UNREF(&_ecore_promise_unref);
+   priv->promise_vtable.value_size_get = EINA_FUNC_PROMISE_VALUE_SIZE_GET(&_ecore_promise_value_size_get);
+   priv->promise_vtable.buffer_get = EINA_FUNC_PROMISE_BUFFER_GET(&_ecore_promise_buffer_get);
+   
    priv->thread_callback_data.data = data;
    priv->thread_callback_data.func_blocking = func_blocking;
    priv->thread_callback_data.func_cancel = func_cancel;
    eina_promise_owner_default_manual_then_set(priv->eina_owner, EINA_TRUE);
+
+   priv->eina_promise = priv->eina_owner->promise_get(priv->eina_owner);
+   priv->eina_promise->ref(priv->eina_promise);
+   priv->ref_count = 0;
+   priv->then_count = 0;
+
    if(func_cancel)
-     eina_promise_owner_default_cancel_cb_add(priv->eina_owner, &_ecore_promise_cancel, priv, NULL);
+     eina_promise_owner_default_cancel_cb_add(priv->eina_owner, &_ecore_promise_cancel_cb, priv, NULL);
    priv->thread_callback_data.thread =
      ecore_thread_feedback_run(&_ecore_promise_thread_blocking, &_ecore_promise_thread_notify,
                                &_ecore_promise_thread_end, &_ecore_promise_thread_cancel, priv,
                                EINA_FALSE);
    if(promise)
-     *promise = priv->eina_owner->promise_get(priv->eina_owner);
+     *promise = priv->eina_promise;
    return priv->thread_callback_data.thread;
 }
index ffa9c98..52c548e 100644 (file)
@@ -87,7 +87,6 @@ static int _eina_main_count = 0;
 static int _eina_main_thread_count = 0;
 #endif
 static int _eina_log_dom = -1;
-void _eina_promise_init(void);
 
 #ifdef ERR
 #undef ERR
@@ -155,6 +154,7 @@ EAPI Eina_Inlist *_eina_tracking = NULL;
    S(cpu);
    S(thread_queue);
    S(rbtree);
+   S(promise);
 /* no model for now
    S(model);
  */
@@ -201,7 +201,8 @@ static const struct eina_desc_setup _eina_desc_setup[] = {
    S(cow),
    S(cpu),
    S(thread_queue),
-   S(rbtree)
+   S(rbtree),
+   S(promise)
 /* no model for now
    S(model)
  */
@@ -300,8 +301,6 @@ eina_init(void)
           }
      }
 
-   _eina_promise_init();
-   
    eina_cpu_count_internal();
 
    eina_log_timing(_eina_log_dom, EINA_LOG_STATE_STOP, EINA_LOG_STATE_INIT);
index 2f83dc4..2fe19a4 100644 (file)
@@ -4,8 +4,17 @@
 
 #include <Eina.h>
 
+#include <eina_private.h>
+
 #include <assert.h>
 
+static int _eina_promise_log_dom = -1;
+
+#ifdef ERR
+#undef ERR
+#endif
+#define ERR(...) EINA_LOG_DOM_ERR(_eina_promise_log_dom, __VA_ARGS__)
+
 typedef struct _Eina_Promise_Then_Cb _Eina_Promise_Then_Cb;
 typedef struct _Eina_Promise_Progress_Cb _Eina_Promise_Progress_Cb;
 typedef struct _Eina_Promise_Cancel_Cb _Eina_Promise_Cancel_Cb;
@@ -29,6 +38,7 @@ struct _Eina_Promise_Progress_Cb
    EINA_INLIST;
 
    Eina_Promise_Progress_Cb callback;
+   Eina_Promise_Free_Cb free;
    void* data;
 };
 
@@ -94,6 +104,22 @@ struct _Eina_Promise_Iterator
    } data;
 };
 
+static void _eina_promise_free_progress_callback_node(void* node)
+{
+   _Eina_Promise_Progress_Cb *progress_cb = node;
+   if(progress_cb->free)
+     progress_cb->free(progress_cb->data);
+   free(progress_cb);
+}
+
+static void _eina_promise_free_progress_notify_callback_node(void* node)
+{
+   _Eina_Promise_Owner_Progress_Notify_Data *progress_notify_cb = node;
+   if(progress_notify_cb->free_cb)
+     progress_notify_cb->free_cb(progress_notify_cb->data);
+   free(progress_notify_cb);
+}
+
 static void _eina_promise_finish(_Eina_Promise_Default_Owner* promise);
 static void _eina_promise_ref(_Eina_Promise_Default* promise);
 static void _eina_promise_unref(_Eina_Promise_Default* promise);
@@ -119,14 +145,14 @@ static void
 _eina_promise_then_calls(_Eina_Promise_Default_Owner* promise)
 {
    _Eina_Promise_Then_Cb* callback;
-   Eina_Inlist* list2;
    Eina_Bool error;
 
    _eina_promise_ref(&promise->promise);
    error = promise->promise.has_errored;
 
-   EINA_INLIST_FOREACH_SAFE(promise->promise.then_callbacks, list2, callback)
+   EINA_INLIST_FREE(promise->promise.then_callbacks, callback)
      {
+       promise->promise.then_callbacks = eina_inlist_remove(promise->promise.then_callbacks, EINA_INLIST_GET(callback));
        if (error)
         {
           if (callback->error_cb)
@@ -136,6 +162,7 @@ _eina_promise_then_calls(_Eina_Promise_Default_Owner* promise)
         {
           (*callback->callback)(callback->data, &promise->value[0]);
         }
+       free(callback);
        _eina_promise_unref(&promise->promise);
      }
    _eina_promise_unref(&promise->promise);
@@ -145,14 +172,15 @@ static void
 _eina_promise_cancel_calls(_Eina_Promise_Default_Owner* promise, Eina_Bool call_cancel EINA_UNUSED)
 {
    _Eina_Promise_Cancel_Cb* callback;
-   Eina_Inlist* list2;
 
-   EINA_INLIST_FOREACH_SAFE(promise->promise.cancel_callbacks, list2, callback)
+   EINA_INLIST_FREE(promise->promise.cancel_callbacks, callback)
      {
-       if (callback->callback)
-        {
-          (*callback->callback)(callback->data, (Eina_Promise_Owner*)promise);
-        }
+        promise->promise.cancel_callbacks = eina_inlist_remove(promise->promise.cancel_callbacks, EINA_INLIST_GET(callback));
+        if (callback->callback)
+          {
+             (*callback->callback)(callback->data, (Eina_Promise_Owner*)promise);
+          }
+        free(callback);
      }
 
    if (!promise->promise.is_manual_then)
@@ -164,15 +192,19 @@ _eina_promise_cancel_calls(_Eina_Promise_Default_Owner* promise, Eina_Bool call_
 static void
 _eina_promise_del(_Eina_Promise_Default_Owner* promise)
 {
-   if (promise->promise.has_finished)
-     {
-        if (promise->promise.value_free_cb)
-          promise->promise.value_free_cb((void*)&promise->value[0]);
-     }
-   else
+   if (!promise->promise.has_finished)
      {
-        _eina_promise_cancel_calls(promise, EINA_TRUE);
+        ERR("Promise is being deleted, despite not being finished yet. This will cause intermitent crashes");
      }
+
+   if (promise->promise.value_free_cb)
+     promise->promise.value_free_cb((void*)&promise->value[0]);
+
+   _eina_promise_free_callback_list(&promise->promise.progress_callbacks,
+                                    &_eina_promise_free_progress_callback_node);
+   _eina_promise_free_callback_list(&promise->promise.progress_notify_callbacks,
+                                    &_eina_promise_free_progress_notify_callback_node);
+   free(promise);
 }
 
 static void *
@@ -234,8 +266,9 @@ _eina_promise_then(_Eina_Promise_Default* p, Eina_Promise_Cb callback,
    if (!promise->promise.is_first_then)
      {
         _eina_promise_ref(p);
-        promise->promise.is_first_then = EINA_FALSE;
      }
+   else
+     promise->promise.is_first_then = EINA_FALSE;
    if (promise->promise.has_finished)
      {
         _eina_promise_then_calls(promise);
@@ -259,6 +292,10 @@ _eina_promise_finish(_Eina_Promise_Default_Owner* promise)
      {
         _eina_promise_then_calls(promise);
      }
+   if(promise->promise.ref == 0)
+     {
+        _eina_promise_del(promise);
+     }
 }
 
 static Eina_Error
@@ -293,7 +330,8 @@ _eina_promise_owner_cancelled_is(_Eina_Promise_Default_Owner const* promise)
 }
 
 static void
-_eina_promise_progress_cb_add(_Eina_Promise_Default* promise, Eina_Promise_Progress_Cb callback, void* data)
+_eina_promise_progress_cb_add(_Eina_Promise_Default* promise, Eina_Promise_Progress_Cb callback, void* data,
+                              Eina_Promise_Free_Cb free_cb)
 {
    _Eina_Promise_Progress_Cb* cb;
    _Eina_Promise_Owner_Progress_Notify_Data* notify_data;
@@ -302,13 +340,15 @@ _eina_promise_progress_cb_add(_Eina_Promise_Default* promise, Eina_Promise_Progr
    cb = malloc(sizeof(struct _Eina_Promise_Progress_Cb));
    cb->callback = callback;
    cb->data = data;
+   cb->free = free_cb;
    promise->progress_callbacks = eina_inlist_append(promise->progress_callbacks, EINA_INLIST_GET(cb));
 
    EINA_INLIST_FOREACH(owner->promise.progress_notify_callbacks, notify_data)
      {
        (*notify_data->callback)(notify_data->data, &owner->owner_vtable);
      }
-   _eina_promise_free_callback_list(&owner->promise.progress_notify_callbacks, &free);
+   _eina_promise_free_callback_list(&owner->promise.progress_notify_callbacks,
+                                    &_eina_promise_free_progress_notify_callback_node);
 }
 
 static void
@@ -393,7 +433,8 @@ _eina_promise_owner_progress(_Eina_Promise_Default_Owner* promise, void* data)
 
    EINA_INLIST_FOREACH_SAFE(promise->promise.progress_callbacks, list2, callback)
      {
-       (*callback->callback)(callback->data, data);
+        if(callback->callback)
+          (*callback->callback)(callback->data, data);
      }
 }
 
@@ -605,6 +646,7 @@ _eina_promise_progress_notify_fulfilled(void* data, Eina_Promise_Owner* p EINA_U
 }
 
 EAPI Eina_Error EINA_ERROR_PROMISE_NO_NOTIFY;
+EAPI Eina_Error EINA_ERROR_PROMISE_CANCEL;
 
 static void
 _eina_promise_progress_notify_failed(void* data)
@@ -666,9 +708,10 @@ eina_promise_pending_is(Eina_Promise const* promise)
 }
 
 EAPI void
-eina_promise_progress_cb_add(Eina_Promise* promise, Eina_Promise_Progress_Cb callback, void* data)
+eina_promise_progress_cb_add(Eina_Promise* promise, Eina_Promise_Progress_Cb callback, void* data,
+                             Eina_Promise_Free_Cb free_cb)
 {
-   promise->progress_cb_add(promise, callback, data);
+   promise->progress_cb_add(promise, callback, data, free_cb);
 }
 
 EAPI void
@@ -739,8 +782,27 @@ eina_promise_owner_progress_notify(Eina_Promise_Owner* promise, Eina_Promise_Pro
 }
 
 static const char EINA_ERROR_PROMISE_NO_NOTIFY_STR[] = "Out of memory";
+static const char EINA_ERROR_PROMISE_CANCEL_STR[] = "Promise cancelled";
 
-void _eina_promise_init()
+Eina_Bool eina_promise_init()
 {
    EINA_ERROR_PROMISE_NO_NOTIFY = eina_error_msg_static_register(EINA_ERROR_PROMISE_NO_NOTIFY_STR);
+   EINA_ERROR_PROMISE_CANCEL = eina_error_msg_static_register(EINA_ERROR_PROMISE_CANCEL_STR);
+
+   _eina_promise_log_dom = eina_log_domain_register("eina_promise",
+                                                    EINA_LOG_COLOR_DEFAULT);
+   if (_eina_promise_log_dom < 0)
+     {
+        EINA_LOG_ERR("Could not register log domain: eina_promise");
+        return EINA_FALSE;
+     }
+
+   return EINA_TRUE;
+}
+
+Eina_Bool eina_promise_shutdown()
+{
+   eina_log_domain_unregister(_eina_promise_log_dom);
+   _eina_promise_log_dom = -1;
+   return EINA_TRUE;
 }
index 75508be..51bdb80 100644 (file)
@@ -71,7 +71,8 @@ typedef Eina_Bool(*Eina_Promise_Pending_Is_Cb)(Eina_Promise const* promise);
 /*
  * @brief Function callback type for promise's progress add function override
  */
-typedef void(*Eina_Promise_Progress_Cb_Add_Cb)(Eina_Promise* promise, Eina_Promise_Progress_Cb callback, void* data);
+typedef void(*Eina_Promise_Progress_Cb_Add_Cb)(Eina_Promise* promise, Eina_Promise_Progress_Cb callback, void* data
+                                               , Eina_Promise_Free_Cb free_cb);
 
 #define EINA_FUNC_PROMISE_PROGRESS_CB_ADD(Function) ((Eina_Promise_Progress_Cb_Add_Cb)Function)
 
@@ -338,7 +339,8 @@ EAPI Eina_Bool eina_promise_pending_is(Eina_Promise const* promise);
  * @param progress The callback to be called when progress is made
  * @param data The private data that will be passed to the progress callback
  */
-EAPI void eina_promise_progress_cb_add(Eina_Promise* promise, Eina_Promise_Progress_Cb progress, void* data);
+EAPI void eina_promise_progress_cb_add(Eina_Promise* promise, Eina_Promise_Progress_Cb progress, void* data,
+                                       Eina_Promise_Free_Cb free_cb);
 
 /*
  * @brief Increments the reference count for the Eina_Promise
@@ -483,6 +485,14 @@ EAPI void eina_promise_owner_default_call_then(Eina_Promise_Owner* promise);
  */
 EAPI extern Eina_Error EINA_ERROR_PROMISE_NO_NOTIFY;
 
+/**
+ * @var EINA_ERROR_PROMISE_CANCEL
+ *
+ * @brief The error identifier corresponding to when a promise was
+ * cancelled before the callback can be called
+ */
+EAPI extern Eina_Error EINA_ERROR_PROMISE_CANCEL;
+
 /*
  * @internal
  */
index f137d65..5a54281 100644 (file)
@@ -378,7 +378,7 @@ START_TEST(ecore_test_promise_progress_promise)
 
    ecore_thread_promise_run(&promise_progress_thread, NULL, NULL, 0, &promise);
 
-   eina_promise_progress_cb_add(promise, &_progress_callback, NULL);
+   eina_promise_progress_cb_add(promise, &_progress_callback, NULL, NULL);
 
    ecore_main_loop_begin();
 
index f21f5ff..59199e1 100644 (file)
@@ -226,7 +226,7 @@ START_TEST(eina_test_promise_progress)
    owner = eina_promise_default_add(0);
 
    promise = eina_promise_owner_promise_get(owner);
-   eina_promise_progress_cb_add(promise, &progress_callback, &progress_ran);
+   eina_promise_progress_cb_add(promise, &progress_callback, &progress_ran, NULL);
 
    eina_promise_owner_progress(owner, &i);
 
@@ -254,8 +254,8 @@ START_TEST(eina_test_promise_progress_notify1)
    eina_promise_owner_progress_notify(owner, &progress_notify, &progress_notify_ran, NULL);
 
    promise = eina_promise_owner_promise_get(owner);
-   eina_promise_progress_cb_add(promise, &progress_callback, NULL); // never run
-   eina_promise_progress_cb_add(promise, &progress_callback, NULL); // never run
+   eina_promise_progress_cb_add(promise, &progress_callback, NULL, NULL); // never run
+   eina_promise_progress_cb_add(promise, &progress_callback, NULL, NULL); // never run
 
    ck_assert(progress_notify_ran);
 
@@ -311,8 +311,8 @@ START_TEST(eina_test_promise_progress_notify3)
                      &_eina_promise_progress_notify_error, &progress_notify_ran);
 
    promise = eina_promise_owner_promise_get(owner);
-   eina_promise_progress_cb_add(promise, &progress_callback, NULL); // never run
-   eina_promise_progress_cb_add(promise, &progress_callback, NULL); // never run
+   eina_promise_progress_cb_add(promise, &progress_callback, NULL, NULL); // never run
+   eina_promise_progress_cb_add(promise, &progress_callback, NULL, NULL); // never run
 
    ck_assert(progress_notify_ran);
 
@@ -320,6 +320,22 @@ START_TEST(eina_test_promise_progress_notify3)
 }
 END_TEST
 
+START_TEST(eina_test_promise_ignored)
+{
+   Eina_Promise_Owner* owner;
+   Eina_Promise* promise;
+
+   eina_init();
+
+   owner = eina_promise_default_add(0);
+   promise = eina_promise_owner_promise_get(owner);
+   eina_promise_unref(promise);
+   eina_promise_owner_value_set(owner, NULL, NULL);
+
+   eina_shutdown();
+}
+END_TEST
+
 void
 eina_test_promise(TCase *tc)
 {
@@ -333,4 +349,5 @@ eina_test_promise(TCase *tc)
    tcase_add_test(tc, eina_test_promise_progress_notify1);
    tcase_add_test(tc, eina_test_promise_progress_notify2);
    tcase_add_test(tc, eina_test_promise_progress_notify3);
+   tcase_add_test(tc, eina_test_promise_ignored);
 }