tasn pushed a commit to branch master.

http://git.enlightenment.org/core/efl.git/commit/?id=25242e6af9b44ce0b31c66396ba1afbc75bb29a8

commit 25242e6af9b44ce0b31c66396ba1afbc75bb29a8
Author: Tom Hacohen <t...@stosb.com>
Date:   Fri Oct 21 15:02:27 2016 +0100

    Eo: Fix references of objects
---
 src/lib/eo/eo.c                      |  8 ++++++--
 src/lib/eo/eo_base_class.c           | 22 +++++++++++++++++-----
 src/lib/eo/eo_private.h              |  2 ++
 src/tests/eo/suite/eo_test_general.c |  4 ++--
 4 files changed, 27 insertions(+), 9 deletions(-)

diff --git a/src/lib/eo/eo.c b/src/lib/eo/eo.c
index 8ce82f3..ad8306d 100644
--- a/src/lib/eo/eo.c
+++ b/src/lib/eo/eo.c
@@ -850,9 +850,13 @@ _efl_add_end(Eo *eo_id, Eina_Bool is_ref, Eina_Bool 
is_fallback)
    Eo *ret = efl_finalize(eo_id);
    ret = _efl_add_internal_end(eo_id, ret);
 
-   if (is_ref && efl_parent_get(eo_id))
+   if (is_ref)
      {
-        efl_ref(eo_id);
+        if (efl_parent_get(eo_id))
+          {
+             efl_ref(eo_id);
+          }
+        _efl_object_parent_sink(eo_id);
      }
 
    if (is_fallback)
diff --git a/src/lib/eo/eo_base_class.c b/src/lib/eo/eo_base_class.c
index f64ebca..bc85105 100644
--- a/src/lib/eo/eo_base_class.c
+++ b/src/lib/eo/eo_base_class.c
@@ -39,6 +39,7 @@ typedef struct
    unsigned short             event_freeze_count;
    Eina_Bool                  deletions_waiting : 1;
    Eina_Bool                  callback_stopped : 1;
+   Eina_Bool                  parent_sunk : 1; // If parent ref has already 
been settled (parent has been set, or we are in add_ref mode
 } Efl_Object_Data;
 
 typedef enum {
@@ -533,9 +534,17 @@ _efl_object_del(const Eo *obj, Efl_Object_Data *pd 
EINA_UNUSED)
      }
 }
 
+void
+_efl_object_parent_sink(Eo *obj)
+{
+   Efl_Object_Data *pd = efl_data_scope_get(obj, EFL_OBJECT_CLASS);
+   pd->parent_sunk = EINA_TRUE;
+}
+
 EOLIAN static void
 _efl_object_parent_set(Eo *obj, Efl_Object_Data *pd, Eo *parent_id)
 {
+   Eo *prev_parent = pd->parent;
    if ((pd->parent == parent_id) ||
        ((parent_id) && (!_eo_id_domain_compatible(parent_id, obj))))
      return;
@@ -552,10 +561,6 @@ _efl_object_parent_set(Eo *obj, Efl_Object_Data *pd, Eo 
*parent_id)
         // this error is highly unlikely so move it out of the normal
         // instruction path to avoid l1 cache pollution
         else goto err_impossible;
-
-        /* Only unref if we don't have a new parent instead and we are not at
-         * the process of deleting the object.*/
-        if (!parent_id && !eo_obj->del_triggered) efl_unref(obj);
      }
 
    /* Set new parent */
@@ -569,16 +574,23 @@ _efl_object_parent_set(Eo *obj, Efl_Object_Data *pd, Eo 
*parent_id)
              pd->parent = parent_id;
              parent_pd->children = eina_inlist_append(parent_pd->children,
                                                       EINA_INLIST_GET(eo_obj));
+             if (!prev_parent && pd->parent_sunk) efl_ref(obj);
+             pd->parent_sunk = EINA_TRUE;
           }
         else
           {
              pd->parent = NULL;
+             if (prev_parent) efl_unref(obj);
              // unlikely this error happens, so move it out of execution path
              // to improve l1 cache efficiency
              goto err_parent;
           }
      }
-   else pd->parent = NULL;
+   else
+     {
+        pd->parent = NULL;
+        if (prev_parent && !eo_obj->del_triggered) efl_unref(obj);
+     }
 
    EO_OBJ_DONE(obj);
    return;
diff --git a/src/lib/eo/eo_private.h b/src/lib/eo/eo_private.h
index 54975ff..035d84c 100644
--- a/src/lib/eo/eo_private.h
+++ b/src/lib/eo/eo_private.h
@@ -196,6 +196,8 @@ typedef struct
    int line;
 } Eo_Xref_Node;
 
+void _efl_object_parent_sink(Eo *obj);
+
 static inline
 Eo *_eo_header_id_get(const Eo_Header *header)
 {
diff --git a/src/tests/eo/suite/eo_test_general.c 
b/src/tests/eo/suite/eo_test_general.c
index 648f733..e142d67 100644
--- a/src/tests/eo/suite/eo_test_general.c
+++ b/src/tests/eo/suite/eo_test_general.c
@@ -611,8 +611,8 @@ START_TEST(efl_refs)
 
    efl_parent_set(obj2, obj);
    efl_parent_set(obj3, obj);
-   ck_assert_int_eq(efl_ref_get(obj2), 1);
-   ck_assert_int_eq(efl_ref_get(obj3), 1);
+   ck_assert_int_eq(efl_ref_get(obj2), 2);
+   ck_assert_int_eq(efl_ref_get(obj3), 2);
 
    efl_del(obj);
    efl_del(obj2);

-- 


Reply via email to