summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVitor Sousa <vitorsousa@expertisesolutions.com.br>2019-05-23 18:41:57 +0000
committerCedric BAIL <cedric.bail@free.fr>2019-05-29 15:53:23 -0700
commita86a0931f16f6a9d5afbff71364048dc859e2dff (patch)
tree9412183d21dab63fb55e9157c95187b1cb46e571
parent343698f7eceb7cc3cfdb21da955abd401adc16a8 (diff)
eo: add events to track the ownership status of an Eo object
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. We also add benchmarks for sharing (i.e. increasing the refcount) and them unsharing objects, in order to evaluate the performance impact of this patch. Reviewed-by: Cedric BAIL <cedric.bail@free.fr> Differential Revision: https://phab.enlightenment.org/D8678
-rw-r--r--src/benchmarks/eo/eo_bench_eo_add.c34
-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.c238
6 files changed, 291 insertions, 0 deletions
diff --git a/src/benchmarks/eo/eo_bench_eo_add.c b/src/benchmarks/eo/eo_bench_eo_add.c
index 963cd3a..77f2ead 100644
--- a/src/benchmarks/eo/eo_bench_eo_add.c
+++ b/src/benchmarks/eo/eo_bench_eo_add.c
@@ -38,10 +38,44 @@ bench_efl_add_jump_by_2(int request)
38 free(objs); 38 free(objs);
39} 39}
40 40
41static void
42bench_efl_add_shared_ownership(int request)
43{
44 int i;
45 Eo **objs = calloc(request, sizeof(Eo *));
46 Eo *p = efl_add_ref(SIMPLE_CLASS, NULL);
47 for (i = 0; i < request; i++)
48 objs[i] = efl_add_ref(SIMPLE_CLASS, p);
49 efl_unref(p);
50 for (i = 0; i < request; i++)
51 efl_unref(objs[i]);
52 free(objs);
53}
54
55static void
56bench_efl_add_shared_ownership_alternative(int request)
57{
58 int i;
59 Eo **objs = calloc(request, sizeof(Eo *));
60 Eo *p = efl_add_ref(SIMPLE_CLASS, NULL);
61 for (i = 0; i < request; i++)
62 objs[i] = efl_add(SIMPLE_CLASS, p);
63 for (i = 0; i < request; i++)
64 efl_ref(objs[i]);
65 for (i = 0; i < request; i++)
66 efl_unref(objs[i]);
67 efl_unref(p);
68 free(objs);
69}
70
41void eo_bench_efl_add(Eina_Benchmark *bench) 71void eo_bench_efl_add(Eina_Benchmark *bench)
42{ 72{
43 eina_benchmark_register(bench, "efl_add_linear", 73 eina_benchmark_register(bench, "efl_add_linear",
44 EINA_BENCHMARK(bench_efl_add_linear), _EO_BENCH_TIMES(1000, 10, 50000)); 74 EINA_BENCHMARK(bench_efl_add_linear), _EO_BENCH_TIMES(1000, 10, 50000));
45 eina_benchmark_register(bench, "efl_add_jump_by_2", 75 eina_benchmark_register(bench, "efl_add_jump_by_2",
46 EINA_BENCHMARK(bench_efl_add_jump_by_2), _EO_BENCH_TIMES(1000, 10, 50000)); 76 EINA_BENCHMARK(bench_efl_add_jump_by_2), _EO_BENCH_TIMES(1000, 10, 50000));
77 eina_benchmark_register(bench, "efl_add_shared_ownership",
78 EINA_BENCHMARK(bench_efl_add_shared_ownership), _EO_BENCH_TIMES(1000, 10, 50000));
79 eina_benchmark_register(bench, "efl_add_shared_ownership_alternative",
80 EINA_BENCHMARK(bench_efl_add_shared_ownership_alternative), _EO_BENCH_TIMES(1000, 10, 50000));
47} 81}
diff --git a/src/lib/eo/efl_object.eo b/src/lib/eo/efl_object.eo
index 1ced422..bea9a0e 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 0113434..db96b24 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))
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 2dc5efc..62a1caf 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 3b046bb..c64dee5 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 224c9c7..381f153 100644
--- a/src/tests/eo/suite/eo_test_lifecycle.c
+++ b/src/tests/eo/suite/eo_test_lifecycle.c
@@ -163,6 +163,238 @@ 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, 1);
317 ck_assert_int_eq(counter.invalidate, 1);
318
319 efl_unref(obj);
320 ck_assert_int_eq(counter.shared, 1);
321 ck_assert_int_eq(counter.unique, 1);
322 ck_assert_int_eq(counter.invalidate, 1);
323}
324EFL_END_TEST
325
326EFL_START_TEST(eo_test_ownership_events_with_parent_invalidate3)
327{
328 OwnershipEventsCounter counter = {0,};
329 Eo *par = efl_add_ref(SIMPLE_CLASS, NULL);
330 Eo *obj = efl_add(SIMPLE_CLASS, par);
331
332 efl_event_callback_add(obj, EFL_EVENT_OWNERSHIP_SHARED, _ownership_shared_event, &counter);
333 efl_event_callback_add(obj, EFL_EVENT_OWNERSHIP_UNIQUE, _ownership_unique_event, &counter);
334 efl_event_callback_add(obj, EFL_EVENT_INVALIDATE, _invalidate_ownership_event, &counter);
335
336 efl_ref(obj);
337 ck_assert_int_eq(counter.shared, 1);
338 ck_assert_int_eq(counter.unique, 0);
339
340 efl_unref(obj);
341 ck_assert_int_eq(counter.shared, 1);
342 ck_assert_int_eq(counter.unique, 1);
343
344 efl_ref(obj);
345 ck_assert_int_eq(counter.shared, 2);
346 ck_assert_int_eq(counter.unique, 1);
347 efl_ref(obj);
348 ck_assert_int_eq(counter.shared, 2);
349 ck_assert_int_eq(counter.unique, 1);
350 ck_assert_int_eq(counter.invalidate, 0);
351
352 /* Kill parent */
353 efl_unref(par);
354 ck_assert_int_eq(counter.shared, 2);
355 ck_assert_int_eq(counter.unique, 1);
356 ck_assert_int_eq(counter.invalidate, 1);
357}
358EFL_END_TEST
359
360EFL_START_TEST(eo_test_ownership_events_self_invalidate)
361{
362 OwnershipEventsCounter counter = {0,};
363 Eo *par = efl_add_ref(SIMPLE_CLASS, NULL);
364 Eo *obj = efl_add(SIMPLE_CLASS, par);
365
366 efl_event_callback_add(obj, EFL_EVENT_OWNERSHIP_SHARED, _ownership_shared_event, &counter);
367 efl_event_callback_add(obj, EFL_EVENT_OWNERSHIP_UNIQUE, _ownership_unique_event, &counter);
368 efl_event_callback_add(obj, EFL_EVENT_INVALIDATE, _invalidate_ownership_event, &counter);
369
370 ck_assert_int_eq(counter.shared, 0);
371 ck_assert_int_eq(counter.unique, 0);
372 ck_assert_int_eq(counter.invalidate, 0);
373
374 efl_ref(obj);
375 ck_assert_int_eq(counter.shared, 1);
376 ck_assert_int_eq(counter.unique, 0);
377 ck_assert_int_eq(counter.invalidate, 0);
378
379 efl_del(obj);
380 ck_assert_int_eq(counter.shared, 1);
381 ck_assert_int_eq(counter.unique, 1);
382 ck_assert_int_eq(counter.invalidate, 1);
383
384 /* Kill parent */
385 efl_unref(par);
386 ck_assert_int_eq(counter.shared, 1);
387 ck_assert_int_eq(counter.unique, 1);
388 ck_assert_int_eq(counter.invalidate, 1);
389
390 efl_unref(obj);
391 ck_assert_int_eq(counter.shared, 1);
392 ck_assert_int_eq(counter.unique, 1);
393 ck_assert_int_eq(counter.invalidate, 1);
394}
395EFL_END_TEST
396
397typedef struct {
166 Eo *par; 398 Eo *par;
167 Eina_Bool called; 399 Eina_Bool called;
168} Invalidating_Test_Helper; 400} Invalidating_Test_Helper;
@@ -216,6 +448,12 @@ void eo_test_lifecycle(TCase *tc)
216 tcase_add_test(tc, eo_test_shutdown_eventting); 448 tcase_add_test(tc, eo_test_shutdown_eventting);
217 tcase_add_test(tc, eo_test_del_in_noref); 449 tcase_add_test(tc, eo_test_del_in_noref);
218 tcase_add_test(tc, eo_test_unref_noref); 450 tcase_add_test(tc, eo_test_unref_noref);
451 tcase_add_test(tc, eo_test_ownership_events);
452 tcase_add_test(tc, eo_test_ownership_events_with_parent);
453 tcase_add_test(tc, eo_test_ownership_events_with_parent_invalidate);
454 tcase_add_test(tc, eo_test_ownership_events_with_parent_invalidate2);
455 tcase_add_test(tc, eo_test_ownership_events_with_parent_invalidate3);
456 tcase_add_test(tc, eo_test_ownership_events_self_invalidate);
219 tcase_add_test(tc, eo_test_invalidating_get); 457 tcase_add_test(tc, eo_test_invalidating_get);
220 tcase_add_test(tc, eo_test_alive_get); 458 tcase_add_test(tc, eo_test_alive_get);
221} 459}