aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVitor Sousa <vitorsousa@expertisesolutions.com.br>2019-04-17 18:44:40 -0300
committerVitor Sousa <vitorsousa@expertisesolutions.com.br>2019-04-25 19:36:47 -0300
commit082c6cf7c6c1ceef0d0d4cc1f81659e2d456bdac (patch)
tree8be354986b13bd16ab6d5a1b1914fba9c4ce2482
parentelm_theme: Check the ref count to delete or unref. (diff)
downloadefl-devs/vitorsousa/eo_ownership_events.tar.gz
eo: add events to track the ownership status of an Eo objectdevs/vitorsousa/eo_ownership_events
Summary: Some user code may want to track an object ownership in regard to whether it is kept by just one owner or shared between many owners. This is specially true for code provided by bindings to other programming languages, where different kinds of resource management may take place. The event `ownership,unique` is triggered whenever the object refcount goes from two to one, as a signal that it has just one owner from now on. The event `ownership,shared` is triggered whenever the object refcount goes from one to two, as a signal that it has multiple owners from now on. It will not trigger when further increasing the refcount to any value beyond two. Reviewers: lauromoura, felipealmeida, cedric, bu5hm4n, segfaultxavi Subscribers: #reviewers, woohyun, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D8678
-rw-r--r--src/lib/eo/efl_object.eo5
-rw-r--r--src/lib/eo/eo.c7
-rw-r--r--src/lib/eo/eo_base_class.c6
-rw-r--r--src/lib/eo/eo_private.h1
-rw-r--r--src/tests/eo/suite/eo_test_lifecycle.c228
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);
}