diff options
-rw-r--r-- | src/lib/eo/efl_object.eo | 5 | ||||
-rw-r--r-- | src/lib/eo/eo.c | 7 | ||||
-rw-r--r-- | src/lib/eo/eo_base_class.c | 6 | ||||
-rw-r--r-- | src/lib/eo/eo_private.h | 1 | ||||
-rw-r--r-- | src/tests/eo/suite/eo_test_lifecycle.c | 228 |
5 files changed, 247 insertions, 0 deletions
diff --git a/src/lib/eo/efl_object.eo b/src/lib/eo/efl_object.eo index cb0a92e70c..680554c9a8 100644 --- a/src/lib/eo/efl_object.eo +++ b/src/lib/eo/efl_object.eo @@ -411,6 +411,11 @@ abstract Efl.Object del @hot: void; [[Object is being deleted. See @.destructor.]] invalidate @hot: void; [[Object is being invalidated and losing its parent. See @.invalidate.]] noref @hot: void; [[Object has lost its last reference, only parent relationship is keeping it alive. Advanced usage.]] + ownership,unique @hot: void; [[Object has lost a reference and only one is left. It has just one owner now. + Triggered whenever the refcount goes from two to one.]] + ownership,shared @hot: void; [[Object has acquired a second reference. It has multiple owners now. + Triggered whenever increasing the refcount from one to two, + it will not trigger by further increasing the refcount beyond two.]] destruct @hot: void; [[Object has been fully destroyed. It can not be used beyond this point. This event should only serve to clean up any reference you keep to the object.]] diff --git a/src/lib/eo/eo.c b/src/lib/eo/eo.c index c16c021ef2..bd41e3f676 100644 --- a/src/lib/eo/eo.c +++ b/src/lib/eo/eo.c @@ -1933,6 +1933,9 @@ efl_ref(const Eo *obj_id) ++(obj->user_refcount); if (EINA_UNLIKELY(obj->user_refcount == 1)) _efl_ref(obj); + else if (EINA_UNLIKELY(obj->ownership_track && obj->user_refcount == 2)) + efl_event_callback_call((Eo *) obj_id, EFL_EVENT_OWNERSHIP_SHARED, NULL); + #ifdef EO_DEBUG _eo_log_obj_ref_op(obj, EO_REF_OP_REF); #endif @@ -1991,6 +1994,10 @@ efl_unref(const Eo *obj_id) } _efl_unref(obj); } + else if (EINA_UNLIKELY(obj->ownership_track && obj->user_refcount == 1 && !obj->is_invalidating && !obj->invalidate)) + { + efl_event_callback_call((Eo *) obj_id, EFL_EVENT_OWNERSHIP_UNIQUE, NULL); + } _apply_auto_unref(obj, obj_id); diff --git a/src/lib/eo/eo_base_class.c b/src/lib/eo/eo_base_class.c index 2dc5efcec5..62a1caf9a2 100644 --- a/src/lib/eo/eo_base_class.c +++ b/src/lib/eo/eo_base_class.c @@ -1179,6 +1179,12 @@ _special_event_count_inc(Eo *obj_id, Efl_Object_Data *pd, const Efl_Callback_Arr } else if (it->desc == EFL_EVENT_DESTRUCT) pd->has_destroyed_event_cb = EINA_TRUE; + else if (it->desc == EFL_EVENT_OWNERSHIP_SHARED || it->desc == EFL_EVENT_OWNERSHIP_UNIQUE) + { + EO_OBJ_POINTER_RETURN(obj_id, obj); + obj->ownership_track = EINA_TRUE; + EO_OBJ_DONE(obj_id); + } } static inline void diff --git a/src/lib/eo/eo_private.h b/src/lib/eo/eo_private.h index 3b046bb302..c64dee5f5e 100644 --- a/src/lib/eo/eo_private.h +++ b/src/lib/eo/eo_private.h @@ -126,6 +126,7 @@ struct _Eo_Object Eina_Bool destructed:1; Eina_Bool manual_free:1; unsigned char auto_unref : 1; // unref after 1 call - hack for parts + Eina_Bool ownership_track:1; }; /* How we search and store the implementations in classes. */ diff --git a/src/tests/eo/suite/eo_test_lifecycle.c b/src/tests/eo/suite/eo_test_lifecycle.c index 224c9c738c..b3164e6a65 100644 --- a/src/tests/eo/suite/eo_test_lifecycle.c +++ b/src/tests/eo/suite/eo_test_lifecycle.c @@ -163,6 +163,228 @@ EFL_START_TEST(eo_test_unref_noref) EFL_END_TEST typedef struct { + int shared, unique, invalidate; +} OwnershipEventsCounter; + +static void +_ownership_shared_event(void *data, const Efl_Event *ev EINA_UNUSED) +{ + OwnershipEventsCounter *counter = data; + ++(counter->shared); +} + +static void +_ownership_unique_event(void *data, const Efl_Event *ev EINA_UNUSED) +{ + OwnershipEventsCounter *counter = data; + ++(counter->unique); +} + +static void +_invalidate_ownership_event(void *data, const Efl_Event *ev EINA_UNUSED) +{ + OwnershipEventsCounter *counter = data; + ++(counter->invalidate); +} + + +EFL_START_TEST(eo_test_ownership_events) +{ + OwnershipEventsCounter counter = {0,}; + Eo *obj = efl_add_ref(SIMPLE_CLASS, NULL); + + efl_event_callback_add(obj, EFL_EVENT_OWNERSHIP_SHARED, _ownership_shared_event, &counter); + efl_event_callback_add(obj, EFL_EVENT_OWNERSHIP_UNIQUE, _ownership_unique_event, &counter); + efl_event_callback_add(obj, EFL_EVENT_INVALIDATE, _invalidate_ownership_event, &counter); + + efl_ref(obj); + ck_assert_int_eq(counter.shared, 1); + ck_assert_int_eq(counter.unique, 0); + + efl_unref(obj); + ck_assert_int_eq(counter.shared, 1); + ck_assert_int_eq(counter.unique, 1); + + efl_ref(obj); + ck_assert_int_eq(counter.shared, 2); + ck_assert_int_eq(counter.unique, 1); + efl_ref(obj); + ck_assert_int_eq(counter.shared, 2); + ck_assert_int_eq(counter.unique, 1); + efl_ref(obj); + ck_assert_int_eq(counter.shared, 2); + ck_assert_int_eq(counter.unique, 1); + + efl_unref(obj); + ck_assert_int_eq(counter.shared, 2); + ck_assert_int_eq(counter.unique, 1); + efl_unref(obj); + ck_assert_int_eq(counter.shared, 2); + ck_assert_int_eq(counter.unique, 1); + efl_unref(obj); + ck_assert_int_eq(counter.shared, 2); + ck_assert_int_eq(counter.unique, 2); + ck_assert_int_eq(counter.invalidate, 0); + + efl_unref(obj); + ck_assert_int_eq(counter.shared, 2); + ck_assert_int_eq(counter.unique, 2); + ck_assert_int_eq(counter.invalidate, 1); +} +EFL_END_TEST + +EFL_START_TEST(eo_test_ownership_events_with_parent) +{ + OwnershipEventsCounter counter = {0,}; + Eo *par = efl_add_ref(SIMPLE_CLASS, NULL); + Eo *obj = efl_add(SIMPLE_CLASS, par); + + efl_event_callback_add(obj, EFL_EVENT_OWNERSHIP_SHARED, _ownership_shared_event, &counter); + efl_event_callback_add(obj, EFL_EVENT_OWNERSHIP_UNIQUE, _ownership_unique_event, &counter); + efl_event_callback_add(obj, EFL_EVENT_INVALIDATE, _invalidate_ownership_event, &counter); + + efl_ref(obj); + ck_assert_int_eq(counter.shared, 1); + ck_assert_int_eq(counter.unique, 0); + + efl_unref(obj); + ck_assert_int_eq(counter.shared, 1); + ck_assert_int_eq(counter.unique, 1); + + efl_ref(obj); + ck_assert_int_eq(counter.shared, 2); + ck_assert_int_eq(counter.unique, 1); + efl_ref(obj); + ck_assert_int_eq(counter.shared, 2); + ck_assert_int_eq(counter.unique, 1); + + efl_unref(obj); + ck_assert_int_eq(counter.shared, 2); + ck_assert_int_eq(counter.unique, 1); + efl_unref(obj); + ck_assert_int_eq(counter.shared, 2); + ck_assert_int_eq(counter.unique, 2); + ck_assert_int_eq(counter.invalidate, 0); + + efl_del(obj); + ck_assert_int_eq(counter.shared, 2); + ck_assert_int_eq(counter.unique, 2); + ck_assert_int_eq(counter.invalidate, 1); + + efl_unref(par); + ck_assert_int_eq(counter.shared, 2); + ck_assert_int_eq(counter.unique, 2); +} +EFL_END_TEST + +EFL_START_TEST(eo_test_ownership_events_with_parent_invalidate) +{ + OwnershipEventsCounter counter = {0,}; + Eo *par = efl_add_ref(SIMPLE_CLASS, NULL); + Eo *obj = efl_add(SIMPLE_CLASS, par); + + efl_event_callback_add(obj, EFL_EVENT_OWNERSHIP_SHARED, _ownership_shared_event, &counter); + efl_event_callback_add(obj, EFL_EVENT_OWNERSHIP_UNIQUE, _ownership_unique_event, &counter); + efl_event_callback_add(obj, EFL_EVENT_INVALIDATE, _invalidate_ownership_event, &counter); + + /* Kill parent */ + efl_unref(par); + ck_assert_int_eq(counter.shared, 0); + ck_assert_int_eq(counter.unique, 0); + ck_assert_int_eq(counter.invalidate, 1); +} +EFL_END_TEST + +EFL_START_TEST(eo_test_ownership_events_with_parent_invalidate2) +{ + OwnershipEventsCounter counter = {0,}; + Eo *par = efl_add_ref(SIMPLE_CLASS, NULL); + Eo *obj = efl_add(SIMPLE_CLASS, par); + + efl_event_callback_add(obj, EFL_EVENT_OWNERSHIP_SHARED, _ownership_shared_event, &counter); + efl_event_callback_add(obj, EFL_EVENT_OWNERSHIP_UNIQUE, _ownership_unique_event, &counter); + efl_event_callback_add(obj, EFL_EVENT_INVALIDATE, _invalidate_ownership_event, &counter); + + efl_ref(obj); + ck_assert_int_eq(counter.shared, 1); + ck_assert_int_eq(counter.unique, 0); + ck_assert_int_eq(counter.invalidate, 0); + + /* Kill parent */ + efl_unref(par); + ck_assert_int_eq(counter.shared, 1); + ck_assert_int_eq(counter.unique, 0); + ck_assert_int_eq(counter.invalidate, 1); +} +EFL_END_TEST + +EFL_START_TEST(eo_test_ownership_events_with_parent_invalidate3) +{ + OwnershipEventsCounter counter = {0,}; + Eo *par = efl_add_ref(SIMPLE_CLASS, NULL); + Eo *obj = efl_add(SIMPLE_CLASS, par); + + efl_event_callback_add(obj, EFL_EVENT_OWNERSHIP_SHARED, _ownership_shared_event, &counter); + efl_event_callback_add(obj, EFL_EVENT_OWNERSHIP_UNIQUE, _ownership_unique_event, &counter); + efl_event_callback_add(obj, EFL_EVENT_INVALIDATE, _invalidate_ownership_event, &counter); + + efl_ref(obj); + ck_assert_int_eq(counter.shared, 1); + ck_assert_int_eq(counter.unique, 0); + + efl_unref(obj); + ck_assert_int_eq(counter.shared, 1); + ck_assert_int_eq(counter.unique, 1); + + efl_ref(obj); + ck_assert_int_eq(counter.shared, 2); + ck_assert_int_eq(counter.unique, 1); + efl_ref(obj); + ck_assert_int_eq(counter.shared, 2); + ck_assert_int_eq(counter.unique, 1); + ck_assert_int_eq(counter.invalidate, 0); + + /* Kill parent */ + efl_unref(par); + ck_assert_int_eq(counter.shared, 2); + ck_assert_int_eq(counter.unique, 1); + ck_assert_int_eq(counter.invalidate, 1); +} +EFL_END_TEST + +EFL_START_TEST(eo_test_ownership_events_self_invalidate) +{ + OwnershipEventsCounter counter = {0,}; + Eo *par = efl_add_ref(SIMPLE_CLASS, NULL); + Eo *obj = efl_add(SIMPLE_CLASS, par); + + efl_event_callback_add(obj, EFL_EVENT_OWNERSHIP_SHARED, _ownership_shared_event, &counter); + efl_event_callback_add(obj, EFL_EVENT_OWNERSHIP_UNIQUE, _ownership_unique_event, &counter); + efl_event_callback_add(obj, EFL_EVENT_INVALIDATE, _invalidate_ownership_event, &counter); + + ck_assert_int_eq(counter.shared, 0); + ck_assert_int_eq(counter.unique, 0); + ck_assert_int_eq(counter.invalidate, 0); + + efl_ref(obj); + ck_assert_int_eq(counter.shared, 1); + ck_assert_int_eq(counter.unique, 0); + ck_assert_int_eq(counter.invalidate, 0); + + efl_del(obj); + ck_assert_int_eq(counter.shared, 1); + ck_assert_int_eq(counter.unique, 0); + ck_assert_int_eq(counter.invalidate, 1); + + /* Kill parent */ + efl_unref(par); + ck_assert_int_eq(counter.shared, 1); + ck_assert_int_eq(counter.unique, 0); + ck_assert_int_eq(counter.invalidate, 1); +} +EFL_END_TEST + +typedef struct { Eo *par; Eina_Bool called; } Invalidating_Test_Helper; @@ -216,6 +438,12 @@ void eo_test_lifecycle(TCase *tc) tcase_add_test(tc, eo_test_shutdown_eventting); tcase_add_test(tc, eo_test_del_in_noref); tcase_add_test(tc, eo_test_unref_noref); + tcase_add_test(tc, eo_test_ownership_events); + tcase_add_test(tc, eo_test_ownership_events_with_parent); + tcase_add_test(tc, eo_test_ownership_events_with_parent_invalidate); + tcase_add_test(tc, eo_test_ownership_events_with_parent_invalidate2); + tcase_add_test(tc, eo_test_ownership_events_with_parent_invalidate3); + tcase_add_test(tc, eo_test_ownership_events_self_invalidate); tcase_add_test(tc, eo_test_invalidating_get); tcase_add_test(tc, eo_test_alive_get); } |