summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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);
}