eo: to avoid mistake in timing, efl_invalidate should always be triggered before any destructor code.

Differential Revision: https://phab.enlightenment.org/D6061
This commit is contained in:
Cedric Bail 2018-04-04 15:37:11 -07:00 committed by Cedric BAIL
parent 0090384ef5
commit 36f8a70041
2 changed files with 67 additions and 33 deletions

View File

@ -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

View File

@ -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);