From 36f8a70041a8a16249a07d5b7131d57a8a6ea95b Mon Sep 17 00:00:00 2001 From: Cedric Bail Date: Wed, 4 Apr 2018 15:37:11 -0700 Subject: [PATCH] eo: to avoid mistake in timing, efl_invalidate should always be triggered before any destructor code. Differential Revision: https://phab.enlightenment.org/D6061 --- src/lib/eo/eo_base_class.c | 76 +++++++++++++++++++++----------------- src/lib/eo/eo_private.h | 24 ++++++++++++ 2 files changed, 67 insertions(+), 33 deletions(-) diff --git a/src/lib/eo/eo_base_class.c b/src/lib/eo/eo_base_class.c index 9b7b1958f2..5d21a429bd 100644 --- a/src/lib/eo/eo_base_class.c +++ b/src/lib/eo/eo_base_class.c @@ -127,26 +127,31 @@ _efl_pending_futures_clear(Efl_Object_Data *pd) } } -// Generate the invalidate event in all case and make sure it happens -// before any user code can change the children invalidate state. This -// make sure that the entire tree of object is valid at the time of -// the invalidate event. static void -_efl_invalidate(Eo *obj) +_efl_object_invalidate(Eo *obj_id, Efl_Object_Data *pd) { - efl_event_callback_call(obj, EFL_EVENT_INVALIDATE, NULL); + Eina_Inlist *l; + _Eo_Object *child; - efl_invalidate(obj); -} - -static void -_efl_object_invalidate(Eo *obj, Efl_Object_Data *pd) -{ _efl_pending_futures_clear(pd); - if (pd->invalidate) return ; - efl_parent_set(obj, NULL); - pd->invalidate = EINA_TRUE; + EO_OBJ_POINTER(obj_id, obj); + if (obj->invalidate) goto end; + + // Invalidate all children too + EINA_INLIST_FOREACH_SAFE(pd->children, l, child) + { + Eo *child_id = _eo_obj_id_get(child); + efl_parent_set(child_id, NULL); + } + + // Finally invalidate itself + efl_parent_set(obj_id, NULL); + + obj->invalidate = EINA_TRUE; + + end: + EO_OBJ_DONE(obj_id); } static void @@ -658,10 +663,11 @@ _efl_object_parent_sink_set(Eo *obj, Eina_Bool sink) } void -_efl_object_reuse(Eo *obj) +_efl_object_reuse(Eo *obj_id) { - Efl_Object_Data *pd = efl_data_scope_get(obj, EFL_OBJECT_CLASS); - pd->invalidate = EINA_FALSE; + EO_OBJ_POINTER(obj_id, obj); + obj->invalidate = EINA_FALSE; + EO_OBJ_DONE(obj_id); } EOLIAN static void @@ -675,10 +681,10 @@ _efl_object_parent_set(Eo *obj, Efl_Object_Data *pd, Eo *parent_id) EO_OBJ_POINTER_GOTO(obj, eo_obj, err_impossible); // Invalidated object can not be bring back to life - if (pd->invalidate) + if (eo_obj->invalidate) { ERR("Call of efl_parent_set(%p, %p) when object is already invalidated.\n", obj, parent_id); - return ; + goto err_impossible; } if (pd->parent) @@ -719,8 +725,8 @@ _efl_object_parent_set(Eo *obj, Efl_Object_Data *pd, Eo *parent_id) } else { - pd->invalidate = EINA_TRUE; - if (prev_parent) _efl_invalidate(obj); + eo_obj->invalidate = EINA_TRUE; + if (prev_parent) _efl_invalidate(eo_obj); pd->parent = NULL; if (prev_parent && !eo_obj->del_triggered) efl_unref(obj); @@ -758,15 +764,22 @@ _efl_object_finalized_get(const Eo *obj_id, Efl_Object_Data *pd EINA_UNUSED) } EOLIAN static Eina_Bool -_efl_object_invalidated_get(const Eo *obj_id EINA_UNUSED, Efl_Object_Data *pd) +_efl_object_invalidated_get(const Eo *obj_id, Efl_Object_Data *pd EINA_UNUSED) { - return pd->invalidate; + Eina_Bool invalidate; + EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, EINA_TRUE); + invalidate = obj->invalidate; + EO_OBJ_DONE(obj_id); + return invalidate; } EOLIAN static Efl_Object * _efl_object_provider_find(const Eo *obj, Efl_Object_Data *pd, const Efl_Object *klass) { - if (pd->invalidate) + Eina_Bool invalidate; + + invalidate = _efl_object_invalidated_get((Eo*) obj, NULL); + if (invalidate) { ERR("Calling efl_provider_find(%p) after the object was invalidated.", obj); return NULL; @@ -2014,11 +2027,15 @@ efl_future_cb_from_desc(const Eo *o, const Efl_Future_Cb_Desc desc) Efl_Future_Pending *pending = NULL; Eina_Future **storage = NULL; Efl_Object_Data *pd; + Eina_Bool invalidate; EINA_SAFETY_ON_NULL_GOTO(o, end); pd = efl_data_scope_get(o, EFL_OBJECT_CLASS); EINA_SAFETY_ON_NULL_GOTO(pd, end); - EINA_SAFETY_ON_TRUE_GOTO(pd->invalidate, end); + EO_OBJ_POINTER_GOTO(o, eo_obj, end); + invalidate = eo_obj->invalidate; + EO_OBJ_DONE(o); + EINA_SAFETY_ON_TRUE_GOTO(invalidate, end); pending = _efl_pending_future_new(); EINA_SAFETY_ON_NULL_GOTO(pending, end); memcpy(&pending->desc, &desc, sizeof(Efl_Future_Cb_Desc)); @@ -2086,13 +2103,6 @@ _efl_object_destructor(Eo *obj, Efl_Object_Data *pd) DBG("%p - %s.", obj, efl_class_name_get(obj)); - // If the object has been invalidated yet, time to do it - // This can happen when the object has no parent and get - // deleted by efl_unref. - if (!pd->invalidate) - _efl_invalidate(obj); - - // special removal - remove from children list by hand after getting // child handle in case unparent method is overridden and does // extra things like removes other children too later on in the list diff --git a/src/lib/eo/eo_private.h b/src/lib/eo/eo_private.h index b3c8390e97..f3c0e582b9 100644 --- a/src/lib/eo/eo_private.h +++ b/src/lib/eo/eo_private.h @@ -115,6 +115,7 @@ struct _Eo_Object Eina_Bool condtor_done:1; Eina_Bool finalized:1; Eina_Bool super:1; + Eina_Bool invalidate:1; Eina_Bool del_triggered:1; Eina_Bool destructed:1; @@ -247,6 +248,24 @@ _eo_condtor_reset(_Eo_Object *obj) obj->condtor_done = EINA_FALSE; } +// Generate the invalidate event in all case and make sure it happens +// before any user code can change the children invalidate state. This +// make sure that the entire tree of object is valid at the time of +// the invalidate event. +static void +_efl_invalidate(_Eo_Object *obj) +{ + Eo *id; + + if (obj->invalidate) return; + + id = _eo_obj_id_get(obj); + + efl_event_callback_call(id, EFL_EVENT_INVALIDATE, NULL); + + efl_invalidate(id); +} + static inline void _efl_del_internal(_Eo_Object *obj, const char *func_name, const char *file, int line) { @@ -255,6 +274,11 @@ _efl_del_internal(_Eo_Object *obj, const char *func_name, const char *file, int const _Efl_Class *klass = obj->klass; + // If the object has been invalidated yet, time to do it + // before any destructor kick in. This can happen when + // the object has no parent and get deleted by efl_unref. + _efl_invalidate(obj); + efl_event_callback_call(_eo_obj_id_get(obj), EFL_EVENT_DEL, NULL); _eo_condtor_reset(obj);