felipealmeida pushed a commit to branch master. http://git.enlightenment.org/core/efl.git/commit/?id=47dea6abc184823df29f4ce0bcdac59aac637bf8
commit 47dea6abc184823df29f4ce0bcdac59aac637bf8 Author: Lauro Moura <lauromo...@expertisesolutions.com.br> Date: Mon Jun 6 02:54:18 2016 -0300 eina: Avoid promise early deletion when cancelled. Cancelling a promise will fulfill it but won't actually free the memory. This memory is under custody of the owner, who must either call value_set or error_set to finish it. --- src/lib/eina/eina_promise.c | 6 +++++- src/tests/ecore/ecore_test_promise.c | 4 +++- src/tests/eina/eina_test_promise.c | 16 ++++++++++++++++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/lib/eina/eina_promise.c b/src/lib/eina/eina_promise.c index 3410048..9e34481 100644 --- a/src/lib/eina/eina_promise.c +++ b/src/lib/eina/eina_promise.c @@ -76,6 +76,7 @@ struct _Eina_Promise_Default Eina_Bool has_finished : 1; Eina_Bool has_errored : 1; + Eina_Bool can_be_deleted : 1; Eina_Bool is_cancelled : 1; Eina_Bool is_manual_then : 1; Eina_Bool is_first_then : 1; @@ -359,6 +360,7 @@ static void _eina_promise_finish(_Eina_Promise_Default_Owner* promise) { promise->promise.has_finished = EINA_TRUE; + promise->promise.can_be_deleted = EINA_TRUE; if (!promise->promise.is_manual_then) { _eina_promise_then_calls(promise); @@ -453,7 +455,7 @@ _eina_promise_ref(_Eina_Promise_Default* p) static void _eina_promise_unref(_Eina_Promise_Default* p) { - if (p->ref == 1 && p->has_finished) + if (p->ref <= 1 && p->has_finished && p->can_be_deleted) { _eina_promise_del(EINA_PROMISE_GET_OWNER(p)); } @@ -540,6 +542,7 @@ eina_promise_value_add(int value_size) p->promise.has_finished = p->promise.has_errored = p->promise.is_cancelled = p->promise.is_manual_then = p->promise.is_pointer = EINA_FALSE; + p->promise.can_be_deleted = EINA_FALSE; p->promise.is_first_then = EINA_TRUE; p->promise.ref = 1; memset(&p->promise.then_callbacks, 0, sizeof(p->promise.then_callbacks)); @@ -587,6 +590,7 @@ eina_promise_add() p->promise.has_finished = p->promise.has_errored = p->promise.is_cancelled = p->promise.is_manual_then = EINA_FALSE; p->promise.is_first_then = p->promise.is_pointer = EINA_TRUE; + p->promise.can_be_deleted = EINA_FALSE; p->promise.ref = 1; memset(&p->promise.then_callbacks, 0, sizeof(p->promise.then_callbacks)); memset(&p->promise.progress_callbacks, 0, sizeof(p->promise.progress_callbacks)); diff --git a/src/tests/ecore/ecore_test_promise.c b/src/tests/ecore/ecore_test_promise.c index 5f2a754..cf9c33f 100644 --- a/src/tests/ecore/ecore_test_promise.c +++ b/src/tests/ecore/ecore_test_promise.c @@ -303,7 +303,7 @@ static void promise_cancel_thread(const void* data, Eina_Promise_Owner* promise eina_lock_release(&v->lock); } -static void _cancel_callback(const void* data, Eina_Promise_Owner* promise EINA_UNUSED, Ecore_Thread* thread EINA_UNUSED) +static void _cancel_callback(const void* data, Eina_Promise_Owner* promise, Ecore_Thread* thread EINA_UNUSED) { _condition_var* v = (void*)data; @@ -311,6 +311,8 @@ static void _cancel_callback(const void* data, Eina_Promise_Owner* promise EINA_ v->boolean = EINA_TRUE; eina_condition_broadcast(&v->condvar); eina_lock_release(&v->lock); + + eina_promise_owner_value_set(promise, NULL, NULL); } static void _cancel_promise_callback(void* data EINA_UNUSED, Eina_Error value) diff --git a/src/tests/eina/eina_test_promise.c b/src/tests/eina/eina_test_promise.c index e2ef1f3..4629869 100644 --- a/src/tests/eina/eina_test_promise.c +++ b/src/tests/eina/eina_test_promise.c @@ -201,6 +201,14 @@ START_TEST(eina_test_promise_cancel_promise) eina_promise_cancel(promise); ck_assert(cancel_ran && ran); + ck_assert(eina_promise_owner_cancelled_is(owner)); + ck_assert(!eina_promise_pending_is(promise)); + ck_assert_int_eq(EINA_ERROR_PROMISE_CANCEL, eina_promise_error_get(promise)); + + // Finally free the owner + eina_promise_owner_value_set(owner, NULL, NULL); + + ck_assert(ran); eina_shutdown(); } @@ -505,6 +513,14 @@ START_TEST(eina_test_pointer_promise_cancel_promise) eina_promise_cancel(promise); ck_assert(cancel_ran && ran); + ck_assert(eina_promise_owner_cancelled_is(owner)); + ck_assert(!eina_promise_pending_is(promise)); + ck_assert_int_eq(EINA_ERROR_PROMISE_CANCEL, eina_promise_error_get(promise)); + + // Free the owner + eina_promise_owner_value_set(owner, NULL, NULL); + + ck_assert(ran); eina_shutdown(); } --