summaryrefslogtreecommitdiff
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
parent3cc9fc481caaae5fa941bff2f43d5f0f5d0bdb25 (diff)
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
411 del @hot: void; [[Object is being deleted. See @.destructor.]] 411 del @hot: void; [[Object is being deleted. See @.destructor.]]
412 invalidate @hot: void; [[Object is being invalidated and losing its parent. See @.invalidate.]] 412 invalidate @hot: void; [[Object is being invalidated and losing its parent. See @.invalidate.]]
413 noref @hot: void; [[Object has lost its last reference, only parent relationship is keeping it alive. Advanced usage.]] 413 noref @hot: void; [[Object has lost its last reference, only parent relationship is keeping it alive. Advanced usage.]]
414 ownership,unique @hot: void; [[Object has lost a reference and only one is left. It has just one owner now.
415 Triggered whenever the refcount goes from two to one.]]
416 ownership,shared @hot: void; [[Object has acquired a second reference. It has multiple owners now.
417 Triggered whenever increasing the refcount from one to two,
418 it will not trigger by further increasing the refcount beyond two.]]
414 destruct @hot: void; [[Object has been fully destroyed. It can not be used 419 destruct @hot: void; [[Object has been fully destroyed. It can not be used
415 beyond this point. This event should only serve to clean up any 420 beyond this point. This event should only serve to clean up any
416 reference you keep to the object.]] 421 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)
1933 ++(obj->user_refcount); 1933 ++(obj->user_refcount);
1934 if (EINA_UNLIKELY(obj->user_refcount == 1)) 1934 if (EINA_UNLIKELY(obj->user_refcount == 1))
1935 _efl_ref(obj); 1935 _efl_ref(obj);
1936 else if (EINA_UNLIKELY(obj->ownership_track && obj->user_refcount == 2))
1937 efl_event_callback_call((Eo *) obj_id, EFL_EVENT_OWNERSHIP_SHARED, NULL);
1938
1936#ifdef EO_DEBUG 1939#ifdef EO_DEBUG
1937 _eo_log_obj_ref_op(obj, EO_REF_OP_REF); 1940 _eo_log_obj_ref_op(obj, EO_REF_OP_REF);
1938#endif 1941#endif
@@ -1991,6 +1994,10 @@ efl_unref(const Eo *obj_id)
1991 } 1994 }
1992 _efl_unref(obj); 1995 _efl_unref(obj);
1993 } 1996 }
1997 else if (EINA_UNLIKELY(obj->ownership_track && obj->user_refcount == 1 && !obj->is_invalidating && !obj->invalidate))
1998 {
1999 efl_event_callback_call((Eo *) obj_id, EFL_EVENT_OWNERSHIP_UNIQUE, NULL);
2000 }
1994 2001
1995 _apply_auto_unref(obj, obj_id); 2002 _apply_auto_unref(obj, obj_id);
1996 2003
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
1179 } 1179 }
1180 else if (it->desc == EFL_EVENT_DESTRUCT) 1180 else if (it->desc == EFL_EVENT_DESTRUCT)
1181 pd->has_destroyed_event_cb = EINA_TRUE; 1181 pd->has_destroyed_event_cb = EINA_TRUE;
1182 else if (it->desc == EFL_EVENT_OWNERSHIP_SHARED || it->desc == EFL_EVENT_OWNERSHIP_UNIQUE)
1183 {
1184 EO_OBJ_POINTER_RETURN(obj_id, obj);
1185 obj->ownership_track = EINA_TRUE;
1186 EO_OBJ_DONE(obj_id);
1187 }
1182} 1188}
1183 1189
1184static inline void 1190static 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
126 Eina_Bool destructed:1; 126 Eina_Bool destructed:1;
127 Eina_Bool manual_free:1; 127 Eina_Bool manual_free:1;
128 unsigned char auto_unref : 1; // unref after 1 call - hack for parts 128 unsigned char auto_unref : 1; // unref after 1 call - hack for parts
129 Eina_Bool ownership_track:1;
129}; 130};
130 131
131/* How we search and store the implementations in classes. */ 132/* 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)
163EFL_END_TEST 163EFL_END_TEST
164 164
165typedef struct { 165typedef struct {
166 int shared, unique, invalidate;
167} OwnershipEventsCounter;
168
169static void
170_ownership_shared_event(void *data, const Efl_Event *ev EINA_UNUSED)
171{
172 OwnershipEventsCounter *counter = data;
173 ++(counter->shared);
174}
175
176static void
177_ownership_unique_event(void *data, const Efl_Event *ev EINA_UNUSED)
178{
179 OwnershipEventsCounter *counter = data;
180 ++(counter->unique);
181}
182
183static void
184_invalidate_ownership_event(void *data, const Efl_Event *ev EINA_UNUSED)
185{
186 OwnershipEventsCounter *counter = data;
187 ++(counter->invalidate);
188}
189
190
191EFL_START_TEST(eo_test_ownership_events)
192{
193 OwnershipEventsCounter counter = {0,};
194 Eo *obj = efl_add_ref(SIMPLE_CLASS, NULL);
195
196 efl_event_callback_add(obj, EFL_EVENT_OWNERSHIP_SHARED, _ownership_shared_event, &counter);
197 efl_event_callback_add(obj, EFL_EVENT_OWNERSHIP_UNIQUE, _ownership_unique_event, &counter);
198 efl_event_callback_add(obj, EFL_EVENT_INVALIDATE, _invalidate_ownership_event, &counter);
199
200 efl_ref(obj);
201 ck_assert_int_eq(counter.shared, 1);
202 ck_assert_int_eq(counter.unique, 0);
203
204 efl_unref(obj);
205 ck_assert_int_eq(counter.shared, 1);
206 ck_assert_int_eq(counter.unique, 1);
207
208 efl_ref(obj);
209 ck_assert_int_eq(counter.shared, 2);
210 ck_assert_int_eq(counter.unique, 1);
211 efl_ref(obj);
212 ck_assert_int_eq(counter.shared, 2);
213 ck_assert_int_eq(counter.unique, 1);
214 efl_ref(obj);
215 ck_assert_int_eq(counter.shared, 2);
216 ck_assert_int_eq(counter.unique, 1);
217
218 efl_unref(obj);
219 ck_assert_int_eq(counter.shared, 2);
220 ck_assert_int_eq(counter.unique, 1);
221 efl_unref(obj);
222 ck_assert_int_eq(counter.shared, 2);
223 ck_assert_int_eq(counter.unique, 1);
224 efl_unref(obj);
225 ck_assert_int_eq(counter.shared, 2);
226 ck_assert_int_eq(counter.unique, 2);
227 ck_assert_int_eq(counter.invalidate, 0);
228
229 efl_unref(obj);
230 ck_assert_int_eq(counter.shared, 2);
231 ck_assert_int_eq(counter.unique, 2);
232 ck_assert_int_eq(counter.invalidate, 1);
233}
234EFL_END_TEST
235
236EFL_START_TEST(eo_test_ownership_events_with_parent)
237{
238 OwnershipEventsCounter counter = {0,};
239 Eo *par = efl_add_ref(SIMPLE_CLASS, NULL);
240 Eo *obj = efl_add(SIMPLE_CLASS, par);
241
242 efl_event_callback_add(obj, EFL_EVENT_OWNERSHIP_SHARED, _ownership_shared_event, &counter);
243 efl_event_callback_add(obj, EFL_EVENT_OWNERSHIP_UNIQUE, _ownership_unique_event, &counter);
244 efl_event_callback_add(obj, EFL_EVENT_INVALIDATE, _invalidate_ownership_event, &counter);
245
246 efl_ref(obj);
247 ck_assert_int_eq(counter.shared, 1);
248 ck_assert_int_eq(counter.unique, 0);
249
250 efl_unref(obj);
251 ck_assert_int_eq(counter.shared, 1);
252 ck_assert_int_eq(counter.unique, 1);
253
254 efl_ref(obj);
255 ck_assert_int_eq(counter.shared, 2);
256 ck_assert_int_eq(counter.unique, 1);
257 efl_ref(obj);
258 ck_assert_int_eq(counter.shared, 2);
259 ck_assert_int_eq(counter.unique, 1);
260
261 efl_unref(obj);
262 ck_assert_int_eq(counter.shared, 2);
263 ck_assert_int_eq(counter.unique, 1);
264 efl_unref(obj);
265 ck_assert_int_eq(counter.shared, 2);
266 ck_assert_int_eq(counter.unique, 2);
267 ck_assert_int_eq(counter.invalidate, 0);
268
269 efl_del(obj);
270 ck_assert_int_eq(counter.shared, 2);
271 ck_assert_int_eq(counter.unique, 2);
272 ck_assert_int_eq(counter.invalidate, 1);
273
274 efl_unref(par);
275 ck_assert_int_eq(counter.shared, 2);
276 ck_assert_int_eq(counter.unique, 2);
277}
278EFL_END_TEST
279
280EFL_START_TEST(eo_test_ownership_events_with_parent_invalidate)
281{
282 OwnershipEventsCounter counter = {0,};
283 Eo *par = efl_add_ref(SIMPLE_CLASS, NULL);
284 Eo *obj = efl_add(SIMPLE_CLASS, par);
285
286 efl_event_callback_add(obj, EFL_EVENT_OWNERSHIP_SHARED, _ownership_shared_event, &counter);
287 efl_event_callback_add(obj, EFL_EVENT_OWNERSHIP_UNIQUE, _ownership_unique_event, &counter);
288 efl_event_callback_add(obj, EFL_EVENT_INVALIDATE, _invalidate_ownership_event, &counter);
289
290 /* Kill parent */
291 efl_unref(par);
292 ck_assert_int_eq(counter.shared, 0);
293 ck_assert_int_eq(counter.unique, 0);
294 ck_assert_int_eq(counter.invalidate, 1);
295}
296EFL_END_TEST
297
298EFL_START_TEST(eo_test_ownership_events_with_parent_invalidate2)
299{
300 OwnershipEventsCounter counter = {0,};
301 Eo *par = efl_add_ref(SIMPLE_CLASS, NULL);
302 Eo *obj = efl_add(SIMPLE_CLASS, par);
303
304 efl_event_callback_add(obj, EFL_EVENT_OWNERSHIP_SHARED, _ownership_shared_event, &counter);
305 efl_event_callback_add(obj, EFL_EVENT_OWNERSHIP_UNIQUE, _ownership_unique_event, &counter);
306 efl_event_callback_add(obj, EFL_EVENT_INVALIDATE, _invalidate_ownership_event, &counter);
307
308 efl_ref(obj);
309 ck_assert_int_eq(counter.shared, 1);
310 ck_assert_int_eq(counter.unique, 0);
311 ck_assert_int_eq(counter.invalidate, 0);
312
313 /* Kill parent */
314 efl_unref(par);
315 ck_assert_int_eq(counter.shared, 1);
316 ck_assert_int_eq(counter.unique, 0);
317 ck_assert_int_eq(counter.invalidate, 1);
318}
319EFL_END_TEST
320
321EFL_START_TEST(eo_test_ownership_events_with_parent_invalidate3)
322{
323 OwnershipEventsCounter counter = {0,};
324 Eo *par = efl_add_ref(SIMPLE_CLASS, NULL);
325 Eo *obj = efl_add(SIMPLE_CLASS, par);
326
327 efl_event_callback_add(obj, EFL_EVENT_OWNERSHIP_SHARED, _ownership_shared_event, &counter);
328 efl_event_callback_add(obj, EFL_EVENT_OWNERSHIP_UNIQUE, _ownership_unique_event, &counter);
329 efl_event_callback_add(obj, EFL_EVENT_INVALIDATE, _invalidate_ownership_event, &counter);
330
331 efl_ref(obj);
332 ck_assert_int_eq(counter.shared, 1);
333 ck_assert_int_eq(counter.unique, 0);
334
335 efl_unref(obj);
336 ck_assert_int_eq(counter.shared, 1);
337 ck_assert_int_eq(counter.unique, 1);
338
339 efl_ref(obj);
340 ck_assert_int_eq(counter.shared, 2);
341 ck_assert_int_eq(counter.unique, 1);
342 efl_ref(obj);
343 ck_assert_int_eq(counter.shared, 2);
344 ck_assert_int_eq(counter.unique, 1);
345 ck_assert_int_eq(counter.invalidate, 0);
346
347 /* Kill parent */
348 efl_unref(par);
349 ck_assert_int_eq(counter.shared, 2);
350 ck_assert_int_eq(counter.unique, 1);
351 ck_assert_int_eq(counter.invalidate, 1);
352}
353EFL_END_TEST
354
355EFL_START_TEST(eo_test_ownership_events_self_invalidate)
356{
357 OwnershipEventsCounter counter = {0,};
358 Eo *par = efl_add_ref(SIMPLE_CLASS, NULL);
359 Eo *obj = efl_add(SIMPLE_CLASS, par);
360
361 efl_event_callback_add(obj, EFL_EVENT_OWNERSHIP_SHARED, _ownership_shared_event, &counter);
362 efl_event_callback_add(obj, EFL_EVENT_OWNERSHIP_UNIQUE, _ownership_unique_event, &counter);
363 efl_event_callback_add(obj, EFL_EVENT_INVALIDATE, _invalidate_ownership_event, &counter);
364
365 ck_assert_int_eq(counter.shared, 0);
366 ck_assert_int_eq(counter.unique, 0);
367 ck_assert_int_eq(counter.invalidate, 0);
368
369 efl_ref(obj);
370 ck_assert_int_eq(counter.shared, 1);
371 ck_assert_int_eq(counter.unique, 0);
372 ck_assert_int_eq(counter.invalidate, 0);
373
374 efl_del(obj);
375 ck_assert_int_eq(counter.shared, 1);
376 ck_assert_int_eq(counter.unique, 0);
377 ck_assert_int_eq(counter.invalidate, 1);
378
379 /* Kill parent */
380 efl_unref(par);
381 ck_assert_int_eq(counter.shared, 1);
382 ck_assert_int_eq(counter.unique, 0);
383 ck_assert_int_eq(counter.invalidate, 1);
384}
385EFL_END_TEST
386
387typedef struct {
166 Eo *par; 388 Eo *par;
167 Eina_Bool called; 389 Eina_Bool called;
168} Invalidating_Test_Helper; 390} Invalidating_Test_Helper;
@@ -216,6 +438,12 @@ void eo_test_lifecycle(TCase *tc)
216 tcase_add_test(tc, eo_test_shutdown_eventting); 438 tcase_add_test(tc, eo_test_shutdown_eventting);
217 tcase_add_test(tc, eo_test_del_in_noref); 439 tcase_add_test(tc, eo_test_del_in_noref);
218 tcase_add_test(tc, eo_test_unref_noref); 440 tcase_add_test(tc, eo_test_unref_noref);
441 tcase_add_test(tc, eo_test_ownership_events);
442 tcase_add_test(tc, eo_test_ownership_events_with_parent);
443 tcase_add_test(tc, eo_test_ownership_events_with_parent_invalidate);
444 tcase_add_test(tc, eo_test_ownership_events_with_parent_invalidate2);
445 tcase_add_test(tc, eo_test_ownership_events_with_parent_invalidate3);
446 tcase_add_test(tc, eo_test_ownership_events_self_invalidate);
219 tcase_add_test(tc, eo_test_invalidating_get); 447 tcase_add_test(tc, eo_test_invalidating_get);
220 tcase_add_test(tc, eo_test_alive_get); 448 tcase_add_test(tc, eo_test_alive_get);
221} 449}