eo: reduce memory use to track event registration and callback call.
authorCedric Bail <cedric.bail@free.fr>
Thu, 17 Oct 2019 19:09:14 +0000 (12:09 -0700)
committerWonki Kim <wonki_.kim@samsung.com>
Mon, 11 Nov 2019 02:20:41 +0000 (11:20 +0900)
Reviewed-by: Marcel Hollerbach <mail@marcel-hollerbach.de>
Differential Revision: https://phab.enlightenment.org/D10482

src/lib/eo/Eo.h
src/lib/eo/eo_base_class.c
src/tests/eo/suite/eo_test_general.c

index 6e30a29..178372e 100644 (file)
@@ -2268,6 +2268,17 @@ EAPI int efl_callbacks_cmp(const Efl_Callback_Array_Item *a, const Efl_Callback_
 #define efl_event_callback_forwarder_add(obj, desc, new_obj) efl_event_callback_forwarder_priority_add(obj, desc, EFL_CALLBACK_PRIORITY_DEFAULT, new_obj)
 
 /**
+ * @brief Count the number of event handler registered for a specific event.
+ *
+ * @param[in] obj The object.
+ * @param[in] desc The specific event.
+ * @return The number of handler registered for this specific events.
+ *
+ * @ingroup Efl_Object
+ */
+EOAPI unsigned int efl_event_callback_count(const Eo *obj, const Efl_Event_Description *desc);
+
+/**
  * @def Replace the previous Eo pointer with new content.
  *
  * @param storage Pointer to the space holding the object to be replaced.
index 9f50d57..a159c65 100644 (file)
@@ -43,6 +43,8 @@ typedef struct
    Eina_Hash                 *schedulers;
 } Efl_Object_Extension;
 
+#define EFL_OBJECT_EVENT_CALLBACK(Event) Eina_Bool event_cb_##Event : 1;
+
 struct _Efl_Object_Data
 {
    Eina_Inlist               *children;
@@ -63,15 +65,18 @@ struct _Efl_Object_Data
    unsigned int               callbacks_count;
 
    unsigned short             event_freeze_count;
-   unsigned short             event_cb_efl_event_callback_add_count;
-   unsigned short             event_cb_efl_event_callback_del_count;
-   unsigned short             event_cb_efl_event_del_count;
-   unsigned short             event_cb_efl_event_noref_count;
-   unsigned short             event_cb_efl_event_invalidate_count;
+
+   EFL_OBJECT_EVENT_CALLBACK(EFL_EVENT_CALLBACK_ADD);
+   EFL_OBJECT_EVENT_CALLBACK(EFL_EVENT_CALLBACK_DEL);
+   EFL_OBJECT_EVENT_CALLBACK(EFL_EVENT_DEL);
+   EFL_OBJECT_EVENT_CALLBACK(EFL_EVENT_NOREF);
+
+   EFL_OBJECT_EVENT_CALLBACK(EFL_EVENT_INVALIDATE);
+   Eina_Bool                  has_destroyed_event_cb : 1; // No proper count: minor optimization triggered at destruction only
    Eina_Bool                  callback_stopped : 1;
    Eina_Bool                  need_cleaning : 1;
+
    Eina_Bool                  allow_parent_unref : 1; // Allows unref to zero even with a parent
-   Eina_Bool                  has_destroyed_event_cb : 1; // No proper count: minor optimization triggered at destruction only
 };
 
 typedef enum
@@ -1233,6 +1238,19 @@ _pointer_hash(const uintptr_t val)
 #endif
 }
 
+#define EFL_OBJECT_EVENT_CB_INC(Obj, It, Pd, Event)     \
+  if (It->desc == Event && !Pd->event_cb_##Event)       \
+    {                                                   \
+       Pd->event_cb_##Event = EINA_TRUE;                \
+    }
+
+#define EFL_OBJECT_EVENT_CB_DEC(Obj, It, Pd, Event)     \
+  if (It->desc == Event && Pd->event_cb_##Event)        \
+    {                                                   \
+       if (!efl_event_callback_count(Obj, Event))       \
+         Pd->event_cb_##Event = EINA_FALSE;             \
+    }
+
 static inline void
 _special_event_count_inc(Eo *obj_id, Efl_Object_Data *pd, const Efl_Callback_Array_Item *it)
 {
@@ -1242,25 +1260,21 @@ _special_event_count_inc(Eo *obj_id, Efl_Object_Data *pd, const Efl_Callback_Arr
 
    pd->callbacks_mask |= 1 << event_hash;
 
-   if      (it->desc == EFL_EVENT_CALLBACK_ADD)
-     CB_COUNT_INC(pd->event_cb_efl_event_callback_add_count);
-   else if (it->desc == EFL_EVENT_CALLBACK_DEL)
-     CB_COUNT_INC(pd->event_cb_efl_event_callback_del_count);
-   else if (it->desc == EFL_EVENT_DEL)
-     CB_COUNT_INC(pd->event_cb_efl_event_del_count);
-   else if (it->desc == EFL_EVENT_NOREF)
+   EFL_OBJECT_EVENT_CB_INC(obj_id, it, pd, EFL_EVENT_CALLBACK_ADD)
+   else EFL_OBJECT_EVENT_CB_INC(obj_id, it, pd, EFL_EVENT_CALLBACK_DEL)
+   else EFL_OBJECT_EVENT_CB_INC(obj_id, it, pd, EFL_EVENT_DEL)
+   else EFL_OBJECT_EVENT_CB_INC(obj_id, it, pd, EFL_EVENT_INVALIDATE)
+   else if (it->desc == EFL_EVENT_NOREF && !pd->event_cb_EFL_EVENT_NOREF)
      {
-        if (pd->event_cb_efl_event_noref_count == 0)
+        if (efl_event_callback_count(obj_id, EFL_EVENT_NOREF) > 0)
           {
              EO_OBJ_POINTER_RETURN(obj_id, obj);
              obj->noref_event = EINA_TRUE;
              EO_OBJ_DONE(obj_id);
-          }
 
-        CB_COUNT_INC(pd->event_cb_efl_event_noref_count);
+             pd->event_cb_EFL_EVENT_NOREF = EINA_TRUE;
+          }
      }
-   else if (it->desc == EFL_EVENT_INVALIDATE)
-     CB_COUNT_INC(pd->event_cb_efl_event_invalidate_count);
    else if (it->desc == EFL_EVENT_DESTRUCT)
      pd->has_destroyed_event_cb = EINA_TRUE;
    else if (it->desc == EFL_EVENT_OWNERSHIP_SHARED || it->desc == EFL_EVENT_OWNERSHIP_UNIQUE)
@@ -1274,23 +1288,19 @@ _special_event_count_inc(Eo *obj_id, Efl_Object_Data *pd, const Efl_Callback_Arr
 static inline void
 _special_event_count_dec(Eo *obj_id, Efl_Object_Data *pd, const Efl_Callback_Array_Item *it)
 {
-   if      (it->desc == EFL_EVENT_CALLBACK_ADD)
-     CB_COUNT_DEC(pd->event_cb_efl_event_callback_add_count);
-   else if (it->desc == EFL_EVENT_CALLBACK_DEL)
-     CB_COUNT_DEC(pd->event_cb_efl_event_callback_del_count);
-   else if (it->desc == EFL_EVENT_DEL)
-     CB_COUNT_DEC(pd->event_cb_efl_event_del_count);
-   else if (it->desc == EFL_EVENT_INVALIDATE)
-     CB_COUNT_DEC(pd->event_cb_efl_event_invalidate_count);
-   else if (it->desc == EFL_EVENT_NOREF)
+   EFL_OBJECT_EVENT_CB_DEC(obj_id, it, pd, EFL_EVENT_CALLBACK_ADD)
+   else EFL_OBJECT_EVENT_CB_DEC(obj_id, it, pd, EFL_EVENT_CALLBACK_DEL)
+   else EFL_OBJECT_EVENT_CB_DEC(obj_id, it, pd, EFL_EVENT_DEL)
+   else EFL_OBJECT_EVENT_CB_DEC(obj_id, it, pd, EFL_EVENT_INVALIDATE)
+   else if (it->desc == EFL_EVENT_NOREF && pd->event_cb_EFL_EVENT_NOREF)
      {
-        CB_COUNT_DEC(pd->event_cb_efl_event_noref_count);
-
-        if (pd->event_cb_efl_event_noref_count == 0)
+        if (efl_event_callback_count(obj_id, EFL_EVENT_NOREF) == 0)
           {
              EO_OBJ_POINTER_RETURN(obj_id, obj);
              obj->noref_event = EINA_FALSE;
              EO_OBJ_DONE(obj_id);
+
+             pd->event_cb_EFL_EVENT_NOREF = EINA_FALSE;
           }
      }
 }
@@ -1299,18 +1309,10 @@ _special_event_count_dec(Eo *obj_id, Efl_Object_Data *pd, const Efl_Callback_Arr
 static void
 _eo_callback_remove(Eo *obj, Efl_Object_Data *pd, Eo_Callback_Description **cb)
 {
+   Eo_Callback_Description *tmp = *cb;
    unsigned int length;
    const Efl_Callback_Array_Item *it;
 
-   if ((*cb)->func_array)
-     {
-        for (it = (*cb)->items.item_array; it->func; it++)
-          _special_event_count_dec(obj, pd, it);
-     }
-   else _special_event_count_dec(obj, pd, &((*cb)->items.item));
-
-   _eo_callback_free(*cb);
-
    length = pd->callbacks_count - (cb - pd->callbacks);
    if (length > 1)
      memmove(cb, cb + 1, (length - 1) * sizeof(Eo_Callback_Description *));
@@ -1323,6 +1325,15 @@ _eo_callback_remove(Eo *obj, Efl_Object_Data *pd, Eo_Callback_Description **cb)
         free(pd->callbacks);
         pd->callbacks = NULL;
      }
+
+   if (tmp->func_array)
+     {
+        for (it = tmp->items.item_array; it->func; it++)
+          _special_event_count_dec(obj, pd, it);
+     }
+   else _special_event_count_dec(obj, pd, &(tmp->items.item));
+
+   _eo_callback_free(tmp);
 }
 
 /* Actually remove, doesn't care about walking list, or delete_me */
@@ -1338,10 +1349,11 @@ _eo_callback_remove_all(Efl_Object_Data *pd)
    pd->callbacks = NULL;
    pd->callbacks_count = 0;
    pd->has_destroyed_event_cb = EINA_FALSE;
-   pd->event_cb_efl_event_callback_add_count = 0;
-   pd->event_cb_efl_event_callback_del_count = 0;
-   pd->event_cb_efl_event_del_count = 0;
-   pd->event_cb_efl_event_noref_count = 0;
+   pd->event_cb_EFL_EVENT_CALLBACK_ADD = EINA_FALSE;
+   pd->event_cb_EFL_EVENT_CALLBACK_DEL = EINA_FALSE;
+   pd->event_cb_EFL_EVENT_DEL = EINA_FALSE;
+   pd->event_cb_EFL_EVENT_NOREF = EINA_FALSE;
+   pd->event_cb_EFL_EVENT_INVALIDATE = EINA_FALSE;
 }
 
 static void
@@ -1492,8 +1504,6 @@ _efl_object_event_callback_priority_add(Eo *obj, Efl_Object_Data *pd,
 
    _eo_callbacks_sorted_insert(pd, cb);
    _special_event_count_inc(obj, pd, &(cb->items.item));
-   if (EINA_UNLIKELY(desc == EFL_EVENT_DESTRUCT))
-     pd->has_destroyed_event_cb = EINA_TRUE;
 
    efl_event_callback_call(obj, EFL_EVENT_CALLBACK_ADD, (void *)arr);
 
@@ -1599,15 +1609,6 @@ _efl_object_event_callback_array_priority_add(Eo *obj, Efl_Object_Data *pd,
    _eo_callbacks_sorted_insert(pd, cb);
    for (it = cb->items.item_array; it->func; it++)
      _special_event_count_inc(obj, pd, it);
-   if (!pd->has_destroyed_event_cb)
-     {
-        for (it = cb->items.item_array; it->func; it++)
-          if (it->desc == EFL_EVENT_DESTRUCT)
-            {
-               pd->has_destroyed_event_cb = EINA_TRUE;
-               break;
-            }
-     }
 
    num = 0;
    for (it = cb->items.item_array; it->func; it++) num++;
@@ -1868,6 +1869,42 @@ EOAPI EFL_FUNC_BODYV_CONST(efl_event_future_scheduler_get,
                            Eina_Future_Scheduler *, 0, EFL_FUNC_CALL(array),
                            Efl_Callback_Array_Item *array);
 
+EOAPI unsigned int
+_efl_object_event_callback_count(const Eo *obj EINA_UNUSED,
+                                 Efl_Object_Data *pd,
+                                 const Efl_Event_Description *desc)
+{
+   unsigned int r = 0;
+   unsigned int idx;
+
+   for (idx = pd->callbacks_count ; idx > 0; idx--)
+     {
+        Eo_Callback_Description **cb;
+
+        cb = pd->callbacks + idx - 1;
+
+        if ((*cb)->func_array)
+          {
+             const Efl_Callback_Array_Item *it;
+
+             for (it = (*cb)->items.item_array; it->func; it++)
+               {
+                  if (it->desc > desc) break;
+                  if (it->desc == desc) r++;
+               }
+          }
+        else
+          {
+             if ((*cb)->items.item.desc == desc) r++;
+          }
+     }
+   return r;
+}
+
+EOAPI EFL_FUNC_BODYV_CONST(efl_event_callback_count,
+                           unsigned int, 0, EFL_FUNC_CALL(desc),
+                           const Efl_Event_Description *desc);
+
 static Eina_Bool
 _cb_desc_match(const Efl_Event_Description *a, const Efl_Event_Description *b, Eina_Bool legacy_compare)
 {
@@ -1877,6 +1914,9 @@ _cb_desc_match(const Efl_Event_Description *a, const Efl_Event_Description *b, E
    return !strcmp(a->name, b->name);
 }
 
+#define EFL_OBJECT_EVENT_CALLBACK_BLOCK(Pd, Desc, Event)                \
+  if ((Desc == Event) && (!(Pd->event_cb_##Event))) return EINA_FALSE;
+
 static inline Eina_Bool
 _event_callback_call(Eo *obj_id, Efl_Object_Data *pd,
                      const Efl_Event_Description *desc,
@@ -1897,16 +1937,11 @@ _event_callback_call(Eo *obj_id, Efl_Object_Data *pd,
    int event_hash;
 
    if (pd->callbacks_count == 0) return EINA_FALSE;
-   else if ((desc == EFL_EVENT_CALLBACK_ADD) &&
-            (pd->event_cb_efl_event_callback_add_count == 0)) return EINA_FALSE;
-   else if ((desc == EFL_EVENT_CALLBACK_DEL) &&
-            (pd->event_cb_efl_event_callback_del_count == 0)) return EINA_FALSE;
-   else if ((desc == EFL_EVENT_DEL) &&
-            (pd->event_cb_efl_event_del_count == 0)) return EINA_FALSE;
-   else if ((desc == EFL_EVENT_INVALIDATE) &&
-            (pd->event_cb_efl_event_invalidate_count == 0)) return EINA_FALSE;
-   else if ((desc == EFL_EVENT_NOREF) &&
-            (pd->event_cb_efl_event_noref_count == 0)) return EINA_FALSE;
+   else EFL_OBJECT_EVENT_CALLBACK_BLOCK(pd, desc, EFL_EVENT_CALLBACK_ADD)
+   else EFL_OBJECT_EVENT_CALLBACK_BLOCK(pd, desc, EFL_EVENT_CALLBACK_DEL)
+   else EFL_OBJECT_EVENT_CALLBACK_BLOCK(pd, desc, EFL_EVENT_DEL)
+   else EFL_OBJECT_EVENT_CALLBACK_BLOCK(pd, desc, EFL_EVENT_INVALIDATE)
+   else EFL_OBJECT_EVENT_CALLBACK_BLOCK(pd, desc, EFL_EVENT_NOREF)
 
    if (!legacy_compare)
      {
@@ -2611,6 +2646,7 @@ _efl_object_class_destructor(Efl_Class *klass EINA_UNUSED)
    EFL_OBJECT_OP_FUNC(efl_event_callback_call, _efl_object_event_callback_call), \
    EFL_OBJECT_OP_FUNC(efl_event_callback_legacy_call, _efl_object_event_callback_legacy_call), \
    EFL_OBJECT_OP_FUNC(efl_event_future_scheduler_get, _efl_object_event_future_scheduler_get), \
+   EFL_OBJECT_OP_FUNC(efl_event_callback_count, _efl_object_event_callback_count), \
    EFL_OBJECT_OP_FUNC(efl_dbg_info_get, _efl_object_dbg_info_get), \
    EFL_OBJECT_OP_FUNC(efl_wref_add, _efl_object_wref_add), \
    EFL_OBJECT_OP_FUNC(efl_wref_del, _efl_object_wref_del), \
index 61bf10b..1494f46 100644 (file)
@@ -1808,9 +1808,9 @@ EFL_START_TEST(efl_object_size)
    // Update this number only if you modified the class size on purpose
 
 #ifdef EO_DEBUG
-   ck_assert_int_le(efl_class_memory_size_get(SIMPLE_CLASS), 180);
-#else
    ck_assert_int_le(efl_class_memory_size_get(SIMPLE_CLASS), 164);
+#else
+   ck_assert_int_le(efl_class_memory_size_get(SIMPLE_CLASS), 148);
 #endif
 }
 EFL_END_TEST