eo_debug: Improve dangling xref debug logs even more
authorJean-Philippe Andre <jp.andre@samsung.com>
Wed, 15 Feb 2017 05:43:35 +0000 (14:43 +0900)
committerJean-Philippe Andre <jp.andre@samsung.com>
Wed, 15 Feb 2017 05:50:50 +0000 (14:50 +0900)
In case of manual free, as is heavily used by Evas, we can't really
print an ERR if there are still references before free has been
called.

This may not be ideal from a pure EO point of view but considering
how Evas uses manual free this is the best solution to avoid
polluting debug logs.

src/lib/eo/eo.c
src/lib/eo/eo_private.h

index 3722152..182a3a4 100644 (file)
@@ -965,16 +965,47 @@ efl_reuse(const Eo *_obj)
 
 
 void
-_eo_free(_Eo_Object *obj)
+_eo_free(_Eo_Object *obj, Eina_Bool manual_free EINA_UNUSED)
 {
    _Efl_Class *klass = (_Efl_Class*) obj->klass;
 
    _eo_log_obj_free(obj);
 
 #ifdef EO_DEBUG
-   if (obj->datarefcount)
+   if (manual_free)
      {
-        ERR("Object %p data still referenced %d time(s).", obj, obj->datarefcount);
+        Eo *obj_id = _eo_obj_id_get(obj);
+        if (obj->datarefcount)
+          {
+             ERR("Object %p data still referenced %d time(s).", obj_id, obj->datarefcount);
+          }
+        while (obj->xrefs)
+          {
+             Eina_Inlist *nitr = obj->xrefs->next;
+             Eo_Xref_Node *xref = EINA_INLIST_CONTAINER_GET(obj->data_xrefs, Eo_Xref_Node);
+             ERR("Object %p is still referenced by object %p. Origin: %s:%d",
+                 obj_id, xref->ref_obj, xref->file, xref->line);
+             eina_freeq_ptr_main_add(xref, free, sizeof(*xref));
+             obj->xrefs = nitr;
+          }
+        while (obj->data_xrefs)
+          {
+             Eina_Inlist *nitr = obj->data_xrefs->next;
+             Eo_Xref_Node *xref = EINA_INLIST_CONTAINER_GET(obj->data_xrefs, Eo_Xref_Node);
+             if (obj_id == xref->ref_obj)
+               {
+                  WRN("Object %p still has a reference to its own data (subclass: %s). Origin: %s:%d",
+                      obj_id, xref->data_klass, xref->file, xref->line);
+               }
+             else
+               {
+                  ERR("Data of object %p (subclass: %s) is still referenced by object %p. Origin: %s:%d",
+                      obj_id, xref->data_klass, xref->ref_obj, xref->file, xref->line);
+               }
+
+             eina_freeq_ptr_main_add(xref, free, sizeof(*xref));
+             obj->data_xrefs = nitr;
+          }
      }
 #endif
    if (_obj_is_override(obj))
@@ -2362,7 +2393,7 @@ efl_manual_free(Eo *obj_id)
    if (obj->manual_free == EINA_FALSE) goto err_manual_free;
    // rare to use goto to keep instruction cache cleaner
    if (!obj->destructed) goto err_not_destructed;
-   _eo_free(obj);
+   _eo_free(obj, EINA_TRUE);
    EO_OBJ_DONE(obj_id);
    return EINA_TRUE;
 
index 7a6ed69..658c79f 100644 (file)
@@ -274,7 +274,7 @@ _obj_is_override(_Eo_Object *obj)
    return (obj->vtable != &obj->klass->vtable);
 }
 
-void _eo_free(_Eo_Object *obj);
+void _eo_free(_Eo_Object *obj, Eina_Bool manual_free);
 
 static inline _Eo_Object *
 _efl_ref(_Eo_Object *obj)
@@ -322,38 +322,43 @@ _efl_unref_internal(_Eo_Object *obj, const char *func_name, const char *file, in
         obj->del_triggered = EINA_TRUE;
 
         _efl_del_internal(obj, func_name, file, line);
-#ifdef EO_DEBUG
-        /* If for some reason it's not empty, clear it. */
-        while (obj->xrefs)
-          {
-             ERR("in %s:%d: func '%s' obj->xrefs is not empty, possibly a bug, please report. - An error will be reported for each xref in the stack.", file, line, func_name);
-             Eina_Inlist *nitr = obj->xrefs->next;
-             eina_freeq_ptr_main_add(EINA_INLIST_CONTAINER_GET(obj->xrefs, Eo_Xref_Node), free, 0);
-             obj->xrefs = nitr;
-          }
-        while (obj->data_xrefs)
+
+        if (EINA_LIKELY(!obj->manual_free))
           {
-             Eina_Inlist *nitr = obj->data_xrefs->next;
-             Eo_Xref_Node *xref = EINA_INLIST_CONTAINER_GET(obj->data_xrefs, Eo_Xref_Node);
+#ifdef EO_DEBUG
+             /* If for some reason it's not empty, clear it. */
              Eo *obj_id = _eo_obj_id_get(obj);
-             if (obj_id == xref->ref_obj)
+             while (obj->xrefs)
                {
-                  WRN("in %s:%d: func '%s' Object %p still has a reference to its own data (subclass: %s). Origin: %s:%d",
-                      file, line, func_name, obj_id, xref->data_klass, xref->file, xref->line);
+                  Eina_Inlist *nitr = obj->xrefs->next;
+                  Eo_Xref_Node *xref = EINA_INLIST_CONTAINER_GET(obj->data_xrefs, Eo_Xref_Node);
+                  ERR("in %s:%d: func '%s' Object %p is still referenced by object %p. Origin: %s:%d",
+                      file, line, func_name, obj_id, xref->ref_obj, xref->file, xref->line);
+                  eina_freeq_ptr_main_add(xref, free, sizeof(*xref));
+                  obj->xrefs = nitr;
                }
-             else
+             while (obj->data_xrefs)
                {
-                  ERR("in %s:%d: func '%s' Data of object %p (subclass: %s) is still referenced by object %p. Origin: %s:%d",
-                      file, line, func_name, obj_id, xref->data_klass, xref->ref_obj, xref->file, xref->line);
+                  Eina_Inlist *nitr = obj->data_xrefs->next;
+                  Eo_Xref_Node *xref = EINA_INLIST_CONTAINER_GET(obj->data_xrefs, Eo_Xref_Node);
+                  if (obj_id == xref->ref_obj)
+                    {
+                       WRN("in %s:%d: func '%s' Object %p still has a reference to its own data (subclass: %s). Origin: %s:%d",
+                           file, line, func_name, obj_id, xref->data_klass, xref->file, xref->line);
+                    }
+                  else
+                    {
+                       ERR("in %s:%d: func '%s' Data of object %p (subclass: %s) is still referenced by object %p. Origin: %s:%d",
+                           file, line, func_name, obj_id, xref->data_klass, xref->ref_obj, xref->file, xref->line);
+                    }
+
+                  eina_freeq_ptr_main_add(xref, free, sizeof(*xref));
+                  obj->data_xrefs = nitr;
                }
-
-             eina_freeq_ptr_main_add(xref, free, sizeof(*xref));
-             obj->data_xrefs = nitr;
-          }
 #endif
 
-        if (!obj->manual_free)
-          _eo_free(obj);
+             _eo_free(obj, EINA_FALSE);
+          }
         else
           _efl_ref(obj); /* If we manual free, we keep a phantom ref. */
      }