diff --git a/src/lib/eo/eo.c b/src/lib/eo/eo.c index f147f0d2c7..50b8e6673f 100644 --- a/src/lib/eo/eo.c +++ b/src/lib/eo/eo.c @@ -697,19 +697,11 @@ _eo_add_internal_start(const char *file, int line, const Eo_Class *klass_id, Eo _eo_condtor_reset(obj); - _eo_ref(obj); + eo_ref(eo_id); + /* Reference for the parent if is_ref is done in _eo_add_end */ eo_parent_set(eo_id, parent_id); - /* If there's a parent. Ref. Eo_add should return an object with either a - * parent ref, or with the lack of, just a ref. */ - { - if (ref && eo_parent_get(eo_id)) - { - _eo_ref(obj); - } - } - /* eo_id can change here. Freeing is done on the resolved object. */ eo_id = eo_constructor(eo_id); if (!eo_id) @@ -724,10 +716,16 @@ _eo_add_internal_start(const char *file, int line, const Eo_Class *klass_id, Eo } else if (eo_id != _eo_obj_id_get(obj)) { + EO_OBJ_POINTER_RETURN_VAL(eo_id, new_obj, NULL); /* We have two refs at this point. */ _eo_unref(obj); - _eo_unref(obj); + eo_del((Eo *) obj->header.id); + _eo_ref(new_obj); + } + + if (ref && eo_parent_get(eo_id)) + { eo_ref(eo_id); } @@ -1374,11 +1372,11 @@ eo_isa(const Eo *eo_id, const Eo_Class *klass_id) EAPI Eo * eo_xref_internal(const char *file, int line, Eo *obj_id, const Eo *ref_obj_id) { - EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, obj_id); - - _eo_ref(obj); + eo_ref(obj_id); #ifdef EO_DEBUG + EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, obj_id); + Eo_Xref_Node *xref = calloc(1, sizeof(*xref)); xref->ref_obj = ref_obj_id; xref->file = file; @@ -1419,7 +1417,7 @@ eo_xunref(Eo *obj_id, const Eo *ref_obj_id) #else (void) ref_obj_id; #endif - _eo_unref(obj); + eo_unref(obj_id); } EAPI Eo * @@ -1427,7 +1425,11 @@ eo_ref(const Eo *obj_id) { EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, (Eo *)obj_id); - _eo_ref(obj); + ++(obj->user_refcount); + if (EINA_UNLIKELY(obj->user_refcount == 1)) + { + _eo_ref(obj); + } return (Eo *)obj_id; } @@ -1436,7 +1438,17 @@ eo_unref(const Eo *obj_id) { EO_OBJ_POINTER_RETURN(obj_id, obj); - _eo_unref(obj); + --(obj->user_refcount); + if (EINA_UNLIKELY(obj->user_refcount <= 0)) + { + if (obj->user_refcount < 0) + { + ERR("Obj:%p. User refcount (%d) < 0. Too many unrefs.", obj, obj->user_refcount); + return; + } + + _eo_unref(obj); + } } EAPI int @@ -1444,7 +1456,7 @@ eo_ref_get(const Eo *obj_id) { EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, 0); - return obj->refcount; + return obj->user_refcount; } EAPI void diff --git a/src/lib/eo/eo_base_class.c b/src/lib/eo/eo_base_class.c index 2e2fe3fb2e..92e10af655 100644 --- a/src/lib/eo/eo_base_class.c +++ b/src/lib/eo/eo_base_class.c @@ -552,7 +552,7 @@ _eo_base_parent_set(Eo *obj, Eo_Base_Data *pd, Eo *parent_id) * the process of deleting the object.*/ if (!parent_id && !eo_obj->del_triggered) { - _eo_unref(eo_obj); + eo_unref(obj); } } diff --git a/src/lib/eo/eo_private.h b/src/lib/eo/eo_private.h index 9958c8210f..d47fcca93a 100644 --- a/src/lib/eo/eo_private.h +++ b/src/lib/eo/eo_private.h @@ -110,6 +110,7 @@ struct _Eo_Object Eo_Del_Intercept del_intercept; short refcount; + short user_refcount; #ifdef EO_DEBUG short datarefcount; #endif @@ -322,8 +323,9 @@ _eo_unref(_Eo_Object *obj) if (obj->del_intercept) { - (obj->refcount)++; - obj->del_intercept(_eo_obj_id_get(obj)); + Eo *obj_id = _eo_obj_id_get(obj); + eo_ref(obj_id); + obj->del_intercept(obj_id); return; } diff --git a/src/tests/eo/suite/eo_test_class_behaviour_errors.c b/src/tests/eo/suite/eo_test_class_behaviour_errors.c index 12c478f454..3b25b389c0 100644 --- a/src/tests/eo/suite/eo_test_class_behaviour_errors.c +++ b/src/tests/eo/suite/eo_test_class_behaviour_errors.c @@ -48,7 +48,7 @@ START_TEST(eo_destructor_unref) Eo *obj = eo_add(klass, NULL); fail_if(!obj); - TEST_EO_ERROR("_eo_unref", "Object %p deletion already triggered. You wrongly call eo_unref() within a destructor."); + TEST_EO_ERROR("eo_unref", "Obj:%p. User refcount (%d) < 0. Too many unrefs."); eo_unref(obj); eina_log_print_cb_set(eina_log_print_cb_stderr, NULL); @@ -80,7 +80,7 @@ START_TEST(eo_destructor_double_del) eo_manual_free_set(obj, EINA_TRUE); fail_if(!obj); - TEST_EO_ERROR("_eo_unref", "Object %p already destructed."); + TEST_EO_ERROR("eo_unref", "Obj:%p. User refcount (%d) < 0. Too many unrefs."); eo_del(obj); eo_del(obj);