From 6d43adaaf4f194dbac6e79853ef79ed76095208e Mon Sep 17 00:00:00 2001 From: Felipe Magno de Almeida Date: Fri, 6 May 2016 16:32:10 -0300 Subject: [PATCH] eina: Fix memory leaks in promise --- src/lib/ecore/ecore_thread_promise.c | 126 +++++++++++++++++++++++++++++++++-- src/lib/eina/eina_main.c | 7 +- src/lib/eina/eina_promise.c | 106 +++++++++++++++++++++++------ src/lib/eina/eina_promise.h | 14 +++- src/tests/ecore/ecore_test_promise.c | 2 +- src/tests/eina/eina_test_promise.c | 27 ++++++-- 6 files changed, 243 insertions(+), 39 deletions(-) diff --git a/src/lib/ecore/ecore_thread_promise.c b/src/lib/ecore/ecore_thread_promise.c index dbc3ce9..1dea1bc 100644 --- a/src/lib/ecore/ecore_thread_promise.c +++ b/src/lib/ecore/ecore_thread_promise.c @@ -7,6 +7,8 @@ #include +#include + 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; } diff --git a/src/lib/eina/eina_main.c b/src/lib/eina/eina_main.c index ffa9c98..52c548e 100644 --- a/src/lib/eina/eina_main.c +++ b/src/lib/eina/eina_main.c @@ -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); diff --git a/src/lib/eina/eina_promise.c b/src/lib/eina/eina_promise.c index 2f83dc4..2fe19a4 100644 --- a/src/lib/eina/eina_promise.c +++ b/src/lib/eina/eina_promise.c @@ -4,8 +4,17 @@ #include +#include + #include +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; } diff --git a/src/lib/eina/eina_promise.h b/src/lib/eina/eina_promise.h index 75508be..51bdb80 100644 --- a/src/lib/eina/eina_promise.h +++ b/src/lib/eina/eina_promise.h @@ -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 */ diff --git a/src/tests/ecore/ecore_test_promise.c b/src/tests/ecore/ecore_test_promise.c index f137d65..5a54281 100644 --- a/src/tests/ecore/ecore_test_promise.c +++ b/src/tests/ecore/ecore_test_promise.c @@ -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(); diff --git a/src/tests/eina/eina_test_promise.c b/src/tests/eina/eina_test_promise.c index f21f5ff..59199e1 100644 --- a/src/tests/eina/eina_test_promise.c +++ b/src/tests/eina/eina_test_promise.c @@ -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); } -- 2.7.4