jpeg pushed a commit to branch master. http://git.enlightenment.org/core/efl.git/commit/?id=9c95eda74869e7bd36a175929c6f6d1b38360c09
commit 9c95eda74869e7bd36a175929c6f6d1b38360c09 Author: Jean-Philippe Andre <[email protected]> Date: Thu Oct 6 16:27:28 2016 +0900 eo: Fix deadlocks with composite objects This happens with shared objects. The situation seems to be: 1. object has composited object a of class A in thread 1 2. call something on object a from thread 2, deadlock In fact, do anything from thread 2 on a shared object and you deadlock. --- src/lib/eo/eo.c | 10 ++++++---- src/lib/eo/eo_base_class.c | 21 +++++++++++---------- src/tests/eo/suite/eo_test_general.c | 28 ++++++++++++++++++++++------ 3 files changed, 39 insertions(+), 20 deletions(-) diff --git a/src/lib/eo/eo.c b/src/lib/eo/eo.c index 6fe2a03..8324b21 100644 --- a/src/lib/eo/eo.c +++ b/src/lib/eo/eo.c @@ -466,12 +466,11 @@ end: Eo *emb_obj_id; EINA_LIST_FOREACH(obj->composite_objects, itr, emb_obj_id) { - _Eo_Object *emb_obj = _eo_obj_pointer_get((Eo_Id)emb_obj_id); - - if (!emb_obj) continue; + EO_OBJ_POINTER(emb_obj_id, emb_obj); + if (EINA_UNLIKELY(!emb_obj)) continue; func = _vtable_func_get(emb_obj->vtable, cache->op); - if (func == NULL) continue; + if (func == NULL) goto composite_continue; if (EINA_LIKELY(func->func && func->src)) { @@ -481,8 +480,11 @@ end: call->data = _efl_data_scope_get(emb_obj, func->src); /* We reffed it above, but no longer need/use it. */ _efl_unref(obj); + EO_OBJ_DONE(emb_obj_id); return EINA_TRUE; } +composite_continue: + EO_OBJ_DONE(emb_obj_id); } } diff --git a/src/lib/eo/eo_base_class.c b/src/lib/eo/eo_base_class.c index e5d9c91..f64ebca 100644 --- a/src/lib/eo/eo_base_class.c +++ b/src/lib/eo/eo_base_class.c @@ -1438,21 +1438,22 @@ _efl_object_event_global_freeze_count_get(Eo *klass EINA_UNUSED, void *pd EINA_U EOLIAN static Eina_Bool _efl_object_composite_attach(Eo *parent_id, Efl_Object_Data *pd EINA_UNUSED, Eo *comp_obj_id) { + Eo *emb_obj_id = NULL; + EO_OBJ_POINTER_RETURN_VAL(comp_obj_id, comp_obj, EINA_FALSE); - EO_OBJ_POINTER(parent_id, parent); - // very unlikely so improve l1 instr cache by using goto - if (!parent) goto err_parent; + EO_OBJ_POINTER_GOTO(parent_id, parent, err_parent); + + /* FIXME: composite should fail if domains are different */ /* Don't composite if we already have a composite object of this type */ { Eina_List *itr; - Eo *emb_obj_id; EINA_LIST_FOREACH(parent->composite_objects, itr, emb_obj_id) { - EO_OBJ_POINTER_RETURN_VAL(emb_obj_id, emb_obj, EINA_FALSE); - // unlikely so improve l1 instr cache by using goto - if (emb_obj->klass == comp_obj->klass) goto err_klass; + EO_OBJ_POINTER_GOTO(emb_obj_id, emb_obj, err_klass); + if (EINA_UNLIKELY(emb_obj->klass == comp_obj->klass)) goto err_klass; } + emb_obj_id = NULL; } Efl_Object_Data *comp_pd = efl_data_scope_get(comp_obj_id, EFL_OBJECT_CLASS); @@ -1466,11 +1467,13 @@ _efl_object_composite_attach(Eo *parent_id, Efl_Object_Data *pd EINA_UNUSED, Eo parent->composite_objects = eina_list_prepend(parent->composite_objects, comp_obj_id); + if (emb_obj_id) EO_OBJ_DONE(emb_obj_id); EO_OBJ_DONE(parent_id); EO_OBJ_DONE(comp_obj_id); return EINA_TRUE; err_klass: + if (emb_obj_id) EO_OBJ_DONE(emb_obj_id); EO_OBJ_DONE(parent_id); err_parent: EO_OBJ_DONE(comp_obj_id); @@ -1481,9 +1484,7 @@ EOLIAN static Eina_Bool _efl_object_composite_detach(Eo *parent_id, Efl_Object_Data *pd EINA_UNUSED, Eo *comp_obj_id) { EO_OBJ_POINTER_RETURN_VAL(comp_obj_id, comp_obj, EINA_FALSE); - EO_OBJ_POINTER(parent_id, parent); - // very unlikely so improve l1 instr cache by using goto - if (!parent) goto err_parent; + EO_OBJ_POINTER_GOTO(parent_id, parent, err_parent); // unlikely so improve l1 instr cache by using goto if (!efl_composite_part_is(comp_obj_id)) goto err_part; diff --git a/src/tests/eo/suite/eo_test_general.c b/src/tests/eo/suite/eo_test_general.c index b0f1bcd..a48192f 100644 --- a/src/tests/eo/suite/eo_test_general.c +++ b/src/tests/eo/suite/eo_test_general.c @@ -1371,7 +1371,7 @@ thr1(void *data, Eina_Thread t EINA_UNUSED) { Data *d = data; Efl_Id_Domain dom; - Eo *objs2; + Eo *s1, *s2; fail_if(efl_domain_switch(EFL_ID_DOMAIN_THREAD) != EINA_TRUE); fail_if(efl_domain_get() != EFL_ID_DOMAIN_THREAD); @@ -1382,12 +1382,28 @@ thr1(void *data, Eina_Thread t EINA_UNUSED) printf("VERIFY finalized_get()\n"); fail_if(!efl_finalized_get(d->objs)); - printf("VERIFY parent_set(invalid)\n"); + printf("VERIFY parent_set(invalid) -- WILL SHOW ERRORS\n"); efl_domain_current_push(EFL_ID_DOMAIN_SHARED); - objs2 = efl_add(DOMAIN_CLASS, NULL); + s1 = efl_add(DOMAIN_CLASS, NULL); efl_domain_current_pop(); - efl_del(objs2); - efl_parent_set(d->objs, objs2); + efl_del(s1); + efl_parent_set(d->objs, s1); + printf("END OF ERRORS\n"); + + printf("VERIFY composite\n"); + efl_domain_current_push(EFL_ID_DOMAIN_SHARED); + s1 = efl_add(SIMPLE_CLASS, NULL, simple_a_set(efl_added, 7)); + s2 = efl_add(SIMPLE_CLASS, NULL, simple_a_set(efl_added, 42)); + efl_domain_current_pop(); + + efl_composite_attach(d->objs, s1); + int i1 = simple_a_get(d->objs); + int i2 = simple_a_get(s1); + fail_if(i1 != i2); + fail_if(efl_composite_attach(d->objs, s2)); + efl_del(s1); + fail_if(!efl_composite_attach(d->objs, s2)); + efl_del(s2); printf("SET ON LOCAL\n"); domain_a_set(obj, 1234); @@ -1430,7 +1446,7 @@ thr1(void *data, Eina_Thread t EINA_UNUSED) static void _timeout(int val EINA_UNUSED) { - printf("TIMED OUT!\n"); + EINA_LOG_CRIT("TIMED OUT!"); exit(-1); } #endif --
