eo: Fix deadlocks with composite objects
authorJean-Philippe Andre <jp.andre@samsung.com>
Thu, 6 Oct 2016 07:27:28 +0000 (16:27 +0900)
committerJean-Philippe Andre <jp.andre@samsung.com>
Thu, 6 Oct 2016 08:57:45 +0000 (17:57 +0900)
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
src/lib/eo/eo_base_class.c
src/tests/eo/suite/eo_test_general.c

index 6fe2a03..8324b21 100644 (file)
@@ -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);
           }
      }
 
index e5d9c91..f64ebca 100644 (file)
@@ -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;
index b0f1bcd..a48192f 100644 (file)
@@ -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