eo: reduce memory use to track event registration and callback call.

Reviewed-by: Marcel Hollerbach <mail@marcel-hollerbach.de>
Differential Revision: https://phab.enlightenment.org/D10482
This commit is contained in:
Cedric Bail 2019-10-17 12:09:14 -07:00 committed by Marcel Hollerbach
parent aacb6bc0c8
commit db93501e66
3 changed files with 113 additions and 66 deletions

View File

@ -2267,6 +2267,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.
*

View 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), \

View 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