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.
This commit is contained in:
Lauro Moura 2016-06-06 02:54:18 -03:00 committed by Felipe Magno de Almeida
parent 2a3d7860db
commit 47dea6abc1
3 changed files with 24 additions and 2 deletions

View File

@ -76,6 +76,7 @@ struct _Eina_Promise_Default
Eina_Bool has_finished : 1; Eina_Bool has_finished : 1;
Eina_Bool has_errored : 1; Eina_Bool has_errored : 1;
Eina_Bool can_be_deleted : 1;
Eina_Bool is_cancelled : 1; Eina_Bool is_cancelled : 1;
Eina_Bool is_manual_then : 1; Eina_Bool is_manual_then : 1;
Eina_Bool is_first_then : 1; Eina_Bool is_first_then : 1;
@ -359,6 +360,7 @@ static void
_eina_promise_finish(_Eina_Promise_Default_Owner* promise) _eina_promise_finish(_Eina_Promise_Default_Owner* promise)
{ {
promise->promise.has_finished = EINA_TRUE; promise->promise.has_finished = EINA_TRUE;
promise->promise.can_be_deleted = EINA_TRUE;
if (!promise->promise.is_manual_then) if (!promise->promise.is_manual_then)
{ {
_eina_promise_then_calls(promise); _eina_promise_then_calls(promise);
@ -453,7 +455,7 @@ _eina_promise_ref(_Eina_Promise_Default* p)
static void static void
_eina_promise_unref(_Eina_Promise_Default* p) _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)); _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.has_finished = p->promise.has_errored =
p->promise.is_cancelled = p->promise.is_manual_then = p->promise.is_pointer = EINA_FALSE; 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.is_first_then = EINA_TRUE;
p->promise.ref = 1; p->promise.ref = 1;
memset(&p->promise.then_callbacks, 0, sizeof(p->promise.then_callbacks)); 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.has_finished = p->promise.has_errored =
p->promise.is_cancelled = p->promise.is_manual_then = EINA_FALSE; p->promise.is_cancelled = p->promise.is_manual_then = EINA_FALSE;
p->promise.is_first_then = p->promise.is_pointer = EINA_TRUE; p->promise.is_first_then = p->promise.is_pointer = EINA_TRUE;
p->promise.can_be_deleted = EINA_FALSE;
p->promise.ref = 1; p->promise.ref = 1;
memset(&p->promise.then_callbacks, 0, sizeof(p->promise.then_callbacks)); memset(&p->promise.then_callbacks, 0, sizeof(p->promise.then_callbacks));
memset(&p->promise.progress_callbacks, 0, sizeof(p->promise.progress_callbacks)); memset(&p->promise.progress_callbacks, 0, sizeof(p->promise.progress_callbacks));

View File

@ -303,7 +303,7 @@ static void promise_cancel_thread(const void* data, Eina_Promise_Owner* promise
eina_lock_release(&v->lock); 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; _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; v->boolean = EINA_TRUE;
eina_condition_broadcast(&v->condvar); eina_condition_broadcast(&v->condvar);
eina_lock_release(&v->lock); 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) static void _cancel_promise_callback(void* data EINA_UNUSED, Eina_Error value)

View File

@ -201,6 +201,14 @@ START_TEST(eina_test_promise_cancel_promise)
eina_promise_cancel(promise); eina_promise_cancel(promise);
ck_assert(cancel_ran && ran); 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(); eina_shutdown();
} }
@ -505,6 +513,14 @@ START_TEST(eina_test_pointer_promise_cancel_promise)
eina_promise_cancel(promise); eina_promise_cancel(promise);
ck_assert(cancel_ran && ran); 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(); eina_shutdown();
} }