diff --git a/configure.ac b/configure.ac index 261a31d66d..23ec83af05 100644 --- a/configure.ac +++ b/configure.ac @@ -338,6 +338,8 @@ AC_SUBST([EINA_SIZEOF_WCHAR_T]) AC_CHECK_SIZEOF(int, 4) AC_CHECK_SIZEOF(long, 4) +AC_CHECK_SIZEOF([uintptr_t]) + AC_CHECK_TYPES([siginfo_t], [], [], [[ #include @@ -1036,6 +1038,19 @@ AC_ARG_ENABLE([fribidi], ], [want_fribidi="yes"]) +# Eo Id +AC_ARG_ENABLE([eo_id], + [AC_HELP_STRING([--disable-eo-id], + [disable Eo indirection. @<:@default=enabled@:>@])], + [ + if test "x${enableval}" = "xyes" ; then + want_eo_id="yes" + else + want_eo_id="no" + fi + ], + [want_eo_id="yes"]) + # Harfbuzz AC_ARG_ENABLE([harfbuzz], [AC_HELP_STRING([--enable-harfbuzz], @@ -3103,6 +3118,10 @@ dnl TODO: remove these ifdefs from code! AC_DEFINE([HAVE_EIO], [1], [Have eio library]) #### End of Eio +# Eo Id +if test "x${want_eo_id}" = "xyes" ; then + AC_DEFINE([HAVE_EO_ID], [1], [Have eo id]) +fi #### EDBus EFL_LIB_START([EDBus]) @@ -3723,6 +3742,8 @@ AC_OUTPUT #### Info +EFL_ADD_FEATURE([EO], [eo-id], [${want_eo_id}]) + case $host_cpu in i*86|x86_64|amd64) EFL_ADD_FEATURE([cpu], [mmx], [${build_cpu_mmx}]) @@ -3775,6 +3796,7 @@ echo " Image Loaders.: ${features_evas_loader}" if test "x${have_pixman}" = "xyes" ; then echo " Pixman........: ${features_evas_pixman}" fi +echo "Eo..............: yes (${features_eo})" echo "Eina............: yes (${features_eina})" echo "Ecore...........: yes (${features_ecore})" echo "Ecore_Con.......: yes (${features_ecore_con})" diff --git a/src/Makefile_Eo.am b/src/Makefile_Eo.am index c0f13076ba..c8e545ea79 100644 --- a/src/Makefile_Eo.am +++ b/src/Makefile_Eo.am @@ -8,6 +8,7 @@ dist_installed_eomainheaders_DATA = lib/eo/Eo.h lib_eo_libeo_la_SOURCES = \ lib/eo/eo.c \ +lib/eo/eo_ptr_indirection.c \ lib/eo/eo_base_class.c \ lib/eo/eo_private.h diff --git a/src/lib/eo/Eo.h b/src/lib/eo/Eo.h index d656774367..fcacfec8a7 100644 --- a/src/lib/eo/Eo.h +++ b/src/lib/eo/Eo.h @@ -218,7 +218,8 @@ EAPI void eo_dbg_info_free(Eo_Dbg_Info *info); * @typedef Eo * The basic Object type. */ -typedef struct _Eo Eo; +typedef struct _Eo_Opaque Eo; + /** * @typedef Eo_Op * The Eo operation type id. @@ -230,14 +231,7 @@ typedef unsigned int Eo_Op; * The basic Object class type. * @ingroup Eo_Class */ -typedef struct _Eo_Class Eo_Class; - -/** - * @typedef Eo_Class_Id - * An Id of a class. - * @ingroup Eo_Class - */ -typedef size_t Eo_Class_Id; +typedef struct _Eo_Class_Opaque Eo_Class; /** * @def EO_NOOP diff --git a/src/lib/eo/eo.c b/src/lib/eo/eo.c index 35e67cfa31..9c90a487c3 100644 --- a/src/lib/eo/eo.c +++ b/src/lib/eo/eo.c @@ -5,6 +5,7 @@ #include #include "Eo.h" +#include "eo_ptr_indirection.h" #include "eo_private.h" /* The last id that should be reserved for statically allocated classes. */ @@ -15,32 +16,44 @@ EAPI Eina_Lock _eo_class_creation_lock; int _eo_log_dom = -1; -static Eo_Class **_eo_classes; +/** + * @typedef Eo_Class_Id + * An Id of a class. + * @ingroup Eo_Class + */ +typedef size_t Eo_Class_Id; + +typedef struct _Eo_Class _Eo_Class; + +static _Eo_Class **_eo_classes; static Eo_Class_Id _eo_classes_last_id; static Eina_Bool _eo_init_count = 0; static Eo_Op _eo_ops_last_id = 0; static size_t _eo_sz = 0; -static void _eo_condtor_reset(Eo *obj); -static inline void *_eo_data_get(const Eo *obj, const Eo_Class *klass); -static inline Eo *_eo_ref(Eo *obj); -static inline void _eo_unref(Eo *obj); -static const Eo_Class *_eo_op_class_get(Eo_Op op); +static void _eo_condtor_reset(_Eo *obj); +static inline void *_eo_data_get(const _Eo *obj, const _Eo_Class *klass); +static inline _Eo *_eo_ref(_Eo *obj); +static inline void _eo_unref(_Eo *obj); +static const _Eo_Class *_eo_op_class_get(Eo_Op op); static const Eo_Op_Description *_eo_op_id_desc_get(Eo_Op op); -struct _Eo { +struct _Eo_Internal { +#ifndef HAVE_EO_ID EINA_MAGIC - EINA_INLIST; +#endif Eo *parent; - Eina_Inlist *children; - const Eo_Class *klass; + Eina_List *children; + const _Eo_Class *klass; #ifdef EO_DEBUG Eina_Inlist *xrefs; #endif Eina_List *composite_objects; + Eo_Id obj_id; + int refcount; Eina_Bool do_error:1; @@ -62,7 +75,7 @@ struct _Eo { #define OP_CLASS_OFFSET_GET(x) (((x) >> EO_OP_CLASS_OFFSET) & 0xffff) #define ID_CLASS_GET(id) ({ \ - (Eo_Class *) ((id <= _eo_classes_last_id) && (id > 0)) ? \ + (_Eo_Class *) ((id <= _eo_classes_last_id) && (id > 0)) ? \ (_eo_classes[id - 1]) : NULL; \ }) @@ -73,7 +86,7 @@ typedef struct _Dich_Chain1 Dich_Chain1; typedef struct { eo_op_func_type func; - const Eo_Class *src; + const _Eo_Class *src; } op_type_funcs; struct _Dich_Chain1 @@ -83,7 +96,7 @@ struct _Dich_Chain1 typedef struct { - const Eo_Class *klass; + const _Eo_Class *klass; size_t offset; } Eo_Extension_Data_Offset; @@ -91,15 +104,15 @@ struct _Eo_Class { EINA_MAGIC Eo_Class_Id class_id; - const Eo_Class *parent; + const _Eo_Class *parent; const Eo_Class_Description *desc; Dich_Chain1 *chain; /**< The size is chain size */ - const Eo_Class **extensions; + const _Eo_Class **extensions; Eo_Extension_Data_Offset *extn_data_off; - const Eo_Class **mro; + const _Eo_Class **mro; unsigned int extn_data_size; unsigned int chain_size; @@ -119,7 +132,7 @@ _dich_chain_alloc(Dich_Chain1 *chain1) } static inline void -_dich_copy_all(Eo_Class *dst, const Eo_Class *src) +_dich_copy_all(_Eo_Class *dst, const _Eo_Class *src) { Eo_Op i; const Dich_Chain1 *sc1 = src->chain; @@ -146,7 +159,7 @@ _dich_copy_all(Eo_Class *dst, const Eo_Class *src) } static inline const op_type_funcs * -_dich_func_get(const Eo_Class *klass, Eo_Op op) +_dich_func_get(const _Eo_Class *klass, Eo_Op op) { size_t idx1 = DICH_CHAIN1(op); if (EINA_UNLIKELY(idx1 >= klass->chain_size)) @@ -158,14 +171,14 @@ _dich_func_get(const Eo_Class *klass, Eo_Op op) } static inline void -_dich_func_set(Eo_Class *klass, Eo_Op op, eo_op_func_type func) +_dich_func_set(_Eo_Class *klass, Eo_Op op, eo_op_func_type func) { size_t idx1 = DICH_CHAIN1(op); Dich_Chain1 *chain1 = &klass->chain[idx1]; _dich_chain_alloc(chain1); if (chain1->funcs[DICH_CHAIN_LAST(op)].src == klass) { - const Eo_Class *op_kls = _eo_op_class_get(op); + const _Eo_Class *op_kls = _eo_op_class_get(op); const Eo_Op_Description *op_desc = _eo_op_id_desc_get(op); ERR("Already set function for op 0x%x (%s:%s). Overriding with func %p", op, op_kls->desc->name, op_desc->name, func); @@ -176,7 +189,7 @@ _dich_func_set(Eo_Class *klass, Eo_Op op, eo_op_func_type func) } static inline void -_dich_func_clean_all(Eo_Class *klass) +_dich_func_clean_all(_Eo_Class *klass) { size_t i; Dich_Chain1 *chain1 = klass->chain; @@ -195,11 +208,31 @@ _dich_func_clean_all(Eo_Class *klass) static const Eo_Op_Description noop_desc = EO_OP_DESCRIPTION(EO_NOOP, "No operation."); -static const Eo_Class * +static inline _Eo_Class * +_eo_class_pointer_get(const Eo_Class *klass_id) +{ +#ifdef HAVE_EO_ID + return ID_CLASS_GET((Eo_Class_Id)klass_id); +#else + return (_Eo_Class *)klass_id; +#endif +} + +static inline +Eo_Class * _eo_class_id_get(const _Eo_Class *klass) +{ +#ifdef HAVE_EO_ID + return (Eo_Class *)klass->class_id; +#else + return (Eo_Class *)klass; +#endif +} + +static const _Eo_Class * _eo_op_class_get(Eo_Op op) { /* FIXME: Make it fast. */ - Eo_Class **itr = _eo_classes; + _Eo_Class **itr = _eo_classes; int mid, max, min; min = 0; @@ -222,7 +255,7 @@ _eo_op_class_get(Eo_Op op) static const Eo_Op_Description * _eo_op_id_desc_get(Eo_Op op) { - const Eo_Class *klass; + const _Eo_Class *klass; if (op == EO_NOOP) return &noop_desc; @@ -246,10 +279,10 @@ _eo_op_id_name_get(Eo_Op op) return (desc) ? desc->name : NULL; } -static inline const Eo_Class * -_eo_kls_itr_next(const Eo_Class *orig_kls, const Eo_Class *cur_klass, Eo_Op op) +static inline const _Eo_Class * +_eo_kls_itr_next(const _Eo_Class *orig_kls, const _Eo_Class *cur_klass, Eo_Op op) { - const Eo_Class **kls_itr = NULL; + const _Eo_Class **kls_itr = NULL; /* Find the kls itr. */ kls_itr = orig_kls->mro; @@ -275,9 +308,9 @@ _eo_kls_itr_next(const Eo_Class *orig_kls, const Eo_Class *cur_klass, Eo_Op op) } static inline const op_type_funcs * -_eo_kls_itr_func_get(const Eo_Class *cur_klass, Eo_Op op) +_eo_kls_itr_func_get(const _Eo_Class *cur_klass, Eo_Op op) { - const Eo_Class *klass = cur_klass; + const _Eo_Class *klass = cur_klass; if (klass) { const op_type_funcs *func = _dich_func_get(klass, op); @@ -294,7 +327,7 @@ _eo_kls_itr_func_get(const Eo_Class *cur_klass, Eo_Op op) #define _EO_OP_ERR_NO_OP_PRINT(file, line, op, klass) \ do \ { \ - const Eo_Class *op_klass = _eo_op_class_get(op); \ + const _Eo_Class *op_klass = _eo_op_class_get(op); \ const char *_dom_name = (op_klass) ? op_klass->desc->name : NULL; \ ERR("in %s:%d: Can't find func for op 0x%x (%s:%s) for class '%s'. Aborting.", \ file, line, op, _dom_name, _eo_op_id_name_get(op), \ @@ -303,7 +336,7 @@ _eo_kls_itr_func_get(const Eo_Class *cur_klass, Eo_Op op) while (0) static Eina_Bool -_eo_op_internal(const char *file, int line, Eo *obj, const Eo_Class *cur_klass, +_eo_op_internal(const char *file, int line, _Eo *obj, const _Eo_Class *cur_klass, Eo_Op_Type op_type, Eo_Op op, va_list *p_list) { #ifdef EO_DEBUG @@ -325,7 +358,7 @@ _eo_op_internal(const char *file, int line, Eo *obj, const Eo_Class *cur_klass, if (EINA_LIKELY(func != NULL)) { void *func_data =_eo_data_get(obj, func->src); - func->func(obj, func_data, p_list); + func->func((Eo *)obj->obj_id, func_data, p_list); return EINA_TRUE; } } @@ -333,10 +366,11 @@ _eo_op_internal(const char *file, int line, Eo *obj, const Eo_Class *cur_klass, /* Try composite objects */ { Eina_List *itr; - Eo *emb_obj; - EINA_LIST_FOREACH(obj->composite_objects, itr, emb_obj) + Eo *emb_obj_id; + EINA_LIST_FOREACH(obj->composite_objects, itr, emb_obj_id) { /* FIXME: Clean this up a bit. */ + EO_OBJ_POINTER_RETURN_VAL(emb_obj_id, emb_obj, EINA_FALSE); if (_eo_op_internal(file, line, emb_obj, emb_obj->klass, op_type, op, p_list)) { return EINA_TRUE; @@ -347,7 +381,7 @@ _eo_op_internal(const char *file, int line, Eo *obj, const Eo_Class *cur_klass, } static inline Eina_Bool -_eo_dov_internal(const char *file, int line, Eo *obj, Eo_Op_Type op_type, va_list *p_list) +_eo_dov_internal(const char *file, int line, _Eo *obj, Eo_Op_Type op_type, va_list *p_list) { Eina_Bool prev_error; Eina_Bool ret = EINA_TRUE; @@ -379,12 +413,12 @@ _eo_dov_internal(const char *file, int line, Eo *obj, Eo_Op_Type op_type, va_lis } EAPI Eina_Bool -eo_do_internal(const char *file, int line, Eo *obj, Eo_Op_Type op_type, ...) +eo_do_internal(const char *file, int line, Eo *obj_id, Eo_Op_Type op_type, ...) { Eina_Bool ret = EINA_TRUE; va_list p_list; - EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, EINA_FALSE); + EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, EINA_FALSE); va_start(p_list, op_type); @@ -396,21 +430,23 @@ eo_do_internal(const char *file, int line, Eo *obj, Eo_Op_Type op_type, ...) } EAPI Eina_Bool -eo_vdo_internal(const char *file, int line, Eo *obj, Eo_Op_Type op_type, va_list *ops) +eo_vdo_internal(const char *file, int line, Eo *obj_id, Eo_Op_Type op_type, va_list *ops) { - EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, EINA_FALSE); + EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, EINA_FALSE); return _eo_dov_internal(file, line, obj, op_type, ops); } EAPI Eina_Bool -eo_do_super_internal(const char *file, int line, Eo *obj, const Eo_Class *cur_klass, +eo_do_super_internal(const char *file, int line, Eo *obj_id, const Eo_Class *cur_klass_id, Eo_Op_Type op_type, Eo_Op op, ...) { - const Eo_Class *nklass; + const _Eo_Class *nklass; Eina_Bool ret = EINA_TRUE; va_list p_list; - EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, EINA_FALSE); + + EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, EINA_FALSE); + _Eo_Class *cur_klass = _eo_class_pointer_get(cur_klass_id); EO_MAGIC_RETURN_VAL(cur_klass, EO_CLASS_EINA_MAGIC, EINA_FALSE); /* Advance the kls itr. */ @@ -431,7 +467,7 @@ eo_do_super_internal(const char *file, int line, Eo *obj, const Eo_Class *cur_kl } static Eina_Bool -_eo_class_op_internal(const char *file, int line, Eo_Class *klass, const Eo_Class *cur_klass, +_eo_class_op_internal(const char *file, int line, _Eo_Class *klass, const _Eo_Class *cur_klass, Eo_Op op, va_list *p_list) { #ifdef EO_DEBUG @@ -455,7 +491,7 @@ _eo_class_op_internal(const char *file, int line, Eo_Class *klass, const Eo_Clas const op_type_funcs *func = _eo_kls_itr_func_get(cur_klass, op); if (func) { - ((eo_op_func_type_class) func->func)(klass, p_list); + ((eo_op_func_type_class) func->func)(_eo_class_id_get(klass), p_list); return EINA_TRUE; } } @@ -464,20 +500,21 @@ _eo_class_op_internal(const char *file, int line, Eo_Class *klass, const Eo_Clas } EAPI Eina_Bool -eo_class_do_internal(const char *file, int line, const Eo_Class *klass, ...) +eo_class_do_internal(const char *file, int line, const Eo_Class *klass_id, ...) { Eina_Bool ret = EINA_TRUE; Eo_Op op = EO_NOOP; va_list p_list; + _Eo_Class *klass = _eo_class_pointer_get(klass_id); EO_MAGIC_RETURN_VAL(klass, EO_CLASS_EINA_MAGIC, EINA_FALSE); - va_start(p_list, klass); + va_start(p_list, klass_id); op = va_arg(p_list, Eo_Op); while (op) { - if (!_eo_class_op_internal(file, line, (Eo_Class *) klass, klass, op, &p_list)) + if (!_eo_class_op_internal(file, line, (_Eo_Class *) klass, klass, op, &p_list)) { _EO_OP_ERR_NO_OP_PRINT(file, line, op, klass); ret = EINA_FALSE; @@ -492,10 +529,12 @@ eo_class_do_internal(const char *file, int line, const Eo_Class *klass, ...) } EAPI Eina_Bool -eo_class_do_super_internal(const char *file, int line, const Eo_Class *klass, - const Eo_Class *cur_klass, Eo_Op op, ...) +eo_class_do_super_internal(const char *file, int line, const Eo_Class *klass_id, + const Eo_Class *cur_klass_id, Eo_Op op, ...) { - const Eo_Class *nklass; + _Eo_Class *klass = _eo_class_pointer_get(klass_id); + _Eo_Class *cur_klass = _eo_class_pointer_get(cur_klass_id); + const _Eo_Class *nklass; Eina_Bool ret = EINA_TRUE; va_list p_list; EO_MAGIC_RETURN_VAL(klass, EO_CLASS_EINA_MAGIC, EINA_FALSE); @@ -505,7 +544,7 @@ eo_class_do_super_internal(const char *file, int line, const Eo_Class *klass, nklass = _eo_kls_itr_next(klass, cur_klass, op); va_start(p_list, op); - if (!_eo_class_op_internal(file, line, (Eo_Class *) klass, nklass, op, &p_list)) + if (!_eo_class_op_internal(file, line, (_Eo_Class *) klass, nklass, op, &p_list)) { _EO_OP_ERR_NO_OP_PRINT(file, line, op, nklass); ret = EINA_FALSE; @@ -516,23 +555,26 @@ eo_class_do_super_internal(const char *file, int line, const Eo_Class *klass, } EAPI const Eo_Class * -eo_class_get(const Eo *obj) +eo_class_get(const Eo *obj_id) { - EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, EINA_FALSE); + EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, NULL); - return obj->klass; + if (obj->klass) + return _eo_class_id_get(obj->klass); + return NULL; } EAPI const char * -eo_class_name_get(const Eo_Class *klass) +eo_class_name_get(const Eo_Class *klass_id) { + _Eo_Class *klass = _eo_class_pointer_get(klass_id); EO_MAGIC_RETURN_VAL(klass, EO_CLASS_EINA_MAGIC, NULL); return klass->desc->name; } static void -_eo_class_base_op_init(Eo_Class *klass) +_eo_class_base_op_init(_Eo_Class *klass) { const Eo_Class_Description *desc = klass->desc; @@ -549,9 +591,9 @@ _eo_class_base_op_init(Eo_Class *klass) #ifdef EO_DEBUG static Eina_Bool -_eo_class_mro_has(const Eo_Class *klass, const Eo_Class *find) +_eo_class_mro_has(const _Eo_Class *klass, const _Eo_Class *find) { - const Eo_Class **itr; + const _Eo_Class **itr; for (itr = klass->mro ; *itr ; itr++) { if (*itr == find) @@ -564,7 +606,7 @@ _eo_class_mro_has(const Eo_Class *klass, const Eo_Class *find) #endif static Eina_List * -_eo_class_mro_add(Eina_List *mro, const Eo_Class *klass) +_eo_class_mro_add(Eina_List *mro, const _Eo_Class *klass) { Eina_List *extn_pos = NULL; Eina_Bool check_consistency = !mro; @@ -575,13 +617,13 @@ _eo_class_mro_add(Eina_List *mro, const Eo_Class *klass) /* ONLY ADD MIXINS! */ - /* Recursively add extenions. */ + /* Recursively add extensions. */ { - const Eo_Class **extn_itr; + const _Eo_Class **extn_itr; for (extn_itr = klass->extensions ; *extn_itr ; extn_itr++) { - const Eo_Class *extn = *extn_itr; + const _Eo_Class *extn = *extn_itr; if (extn->desc->type != EO_CLASS_TYPE_MIXIN) continue; @@ -599,12 +641,12 @@ _eo_class_mro_add(Eina_List *mro, const Eo_Class *klass) * we are working on (i.e no parents). */ if (check_consistency) { - const Eo_Class **extn_itr; + const _Eo_Class **extn_itr; Eina_List *itr = extn_pos; for (extn_itr = klass->extensions ; *extn_itr ; extn_itr++) { - const Eo_Class *extn = *extn_itr; + const _Eo_Class *extn = *extn_itr; if (extn->desc->type != EO_CLASS_TYPE_MIXIN) continue; @@ -631,7 +673,7 @@ _eo_class_mro_add(Eina_List *mro, const Eo_Class *klass) } static Eina_Bool -_eo_class_mro_init(Eo_Class *klass) +_eo_class_mro_init(_Eo_Class *klass) { Eina_List *mro = NULL; @@ -668,8 +710,8 @@ _eo_class_mro_init(Eo_Class *klass) /* Copy the mro and free the list. */ { - const Eo_Class *kls_itr; - const Eo_Class **mro_itr; + const _Eo_Class *kls_itr; + const _Eo_Class **mro_itr; klass->mro = calloc(sizeof(*klass->mro), eina_list_count(mro) + 1); mro_itr = klass->mro; @@ -689,7 +731,7 @@ _eo_class_mro_init(Eo_Class *klass) } static void -_eo_class_constructor(Eo_Class *klass) +_eo_class_constructor(_Eo_Class *klass) { if (klass->constructed) return; @@ -697,12 +739,13 @@ _eo_class_constructor(Eo_Class *klass) klass->constructed = EINA_TRUE; if (klass->desc->class_constructor) - klass->desc->class_constructor(klass); + klass->desc->class_constructor(_eo_class_id_get(klass)); } EAPI void -eo_class_funcs_set(Eo_Class *klass, const Eo_Op_Func_Description *func_descs) +eo_class_funcs_set(Eo_Class *klass_id, const Eo_Op_Func_Description *func_descs) { + _Eo_Class *klass = _eo_class_pointer_get(klass_id); EO_MAGIC_RETURN(klass, EO_CLASS_EINA_MAGIC); const Eo_Op_Func_Description *itr; @@ -735,12 +778,12 @@ eo_class_funcs_set(Eo_Class *klass, const Eo_Op_Func_Description *func_descs) } static void -eo_class_free(Eo_Class *klass) +eo_class_free(_Eo_Class *klass) { if (klass->constructed) { if (klass->desc->class_destructor) - klass->desc->class_destructor(klass); + klass->desc->class_destructor(_eo_class_id_get(klass)); _dich_func_clean_all(klass); } @@ -758,7 +801,7 @@ eo_class_free(Eo_Class *klass) /* DEVCHECK */ static Eina_Bool -_eo_class_check_op_descs(const Eo_Class *klass) +_eo_class_check_op_descs(const _Eo_Class *klass) { const Eo_Class_Description *desc = klass->desc; const Eo_Op_Description *itr; @@ -809,24 +852,25 @@ _eo_class_check_op_descs(const Eo_Class *klass) /* Not really called, just used for the ptr... */ static void -_eo_class_isa_func(Eo *obj EINA_UNUSED, void *class_data EINA_UNUSED, va_list *list EINA_UNUSED) +_eo_class_isa_func(Eo *obj_id EINA_UNUSED, void *class_data EINA_UNUSED, va_list *list EINA_UNUSED) { /* Do nonthing. */ } EAPI const Eo_Class * -eo_class_new(const Eo_Class_Description *desc, const Eo_Class *parent, ...) +eo_class_new(const Eo_Class_Description *desc, const Eo_Class *parent_id, ...) { - Eo_Class *klass; + _Eo_Class *klass; va_list p_list; + _Eo_Class *parent = _eo_class_pointer_get(parent_id); if (parent && !EINA_MAGIC_CHECK(parent, EO_CLASS_EINA_MAGIC)) { EINA_MAGIC_FAIL(parent, EO_CLASS_EINA_MAGIC); return NULL; } - va_start(p_list, parent); + va_start(p_list, parent_id); EINA_SAFETY_ON_NULL_RETURN_VAL(desc, NULL); EINA_SAFETY_ON_NULL_RETURN_VAL(desc->name, NULL); @@ -837,18 +881,20 @@ eo_class_new(const Eo_Class_Description *desc, const Eo_Class *parent, ...) EINA_SAFETY_ON_FALSE_RETURN_VAL(!desc->data_size, NULL); } - klass = calloc(1, sizeof(Eo_Class)); + klass = calloc(1, sizeof(_Eo_Class)); klass->parent = parent; /* Handle class extensions */ { Eina_List *extn_list = NULL; - const Eo_Class *extn = NULL; - const Eo_Class **extn_itr = NULL; + const Eo_Class_Id *extn_id = NULL; + const _Eo_Class *extn = NULL; + const _Eo_Class **extn_itr = NULL; - extn = va_arg(p_list, Eo_Class *); - while (extn) + extn_id = va_arg(p_list, Eo_Class_Id *); + while (extn_id) { + extn = _eo_class_pointer_get((Eo_Class *)extn_id); switch (extn->desc->type) { case EO_CLASS_TYPE_REGULAR: @@ -859,7 +905,7 @@ eo_class_new(const Eo_Class_Description *desc, const Eo_Class *parent, ...) break; } - extn = va_arg(p_list, Eo_Class *); + extn_id = va_arg(p_list, Eo_Class_Id *); } klass->extensions = calloc(sizeof(*klass->extensions), @@ -919,7 +965,7 @@ eo_class_new(const Eo_Class_Description *desc, const Eo_Class *parent, ...) /* create MIXIN offset table. */ { - const Eo_Class **mro_itr = klass->mro; + const _Eo_Class **mro_itr = klass->mro; Eo_Extension_Data_Offset *extn_data_itr; size_t extn_num = 0; size_t extn_data_off = klass->data_offset + @@ -965,7 +1011,7 @@ eo_class_new(const Eo_Class_Description *desc, const Eo_Class *parent, ...) { /* FIXME: Handle errors. */ size_t arrsize = _eo_classes_last_id * sizeof(*_eo_classes); - Eo_Class **tmp; + _Eo_Class **tmp; tmp = realloc(_eo_classes, arrsize); /* If it's the first allocation, memset. */ @@ -982,7 +1028,7 @@ eo_class_new(const Eo_Class_Description *desc, const Eo_Class *parent, ...) _eo_class_base_op_init(klass); /* Flatten the function array */ { - const Eo_Class **mro_itr = klass->mro; + const _Eo_Class **mro_itr = klass->mro; for ( ; *mro_itr ; mro_itr++) ; @@ -995,11 +1041,11 @@ eo_class_new(const Eo_Class_Description *desc, const Eo_Class *parent, ...) /* Mark which classes we implement */ { - const Eo_Class **extn_itr; + const _Eo_Class **extn_itr; for (extn_itr = klass->extensions ; *extn_itr ; extn_itr++) { - const Eo_Class *extn = *extn_itr; + const _Eo_Class *extn = *extn_itr; /* Set it in the dich. */ _dich_func_set(klass, extn->base_id + extn->desc->ops.count, _eo_class_isa_func); @@ -1027,7 +1073,7 @@ eo_class_new(const Eo_Class_Description *desc, const Eo_Class *parent, ...) va_end(p_list); - return klass; + return _eo_class_id_get(klass); cleanup: eo_class_free(klass); @@ -1035,9 +1081,10 @@ cleanup: } EAPI Eina_Bool -eo_isa(const Eo *obj, const Eo_Class *klass) +eo_isa(const Eo *obj_id, const Eo_Class *klass_id) { - EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, EINA_FALSE); + EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, EINA_FALSE); + _Eo_Class *klass = _eo_class_pointer_get(klass_id); EO_MAGIC_RETURN_VAL(klass, EO_CLASS_EINA_MAGIC, EINA_FALSE); const op_type_funcs *func = _dich_func_get(obj->klass, klass->base_id + klass->desc->ops.count); @@ -1048,35 +1095,37 @@ eo_isa(const Eo *obj, const Eo_Class *klass) } EAPI Eina_Bool -eo_parent_set(Eo *obj, const Eo *parent) +eo_parent_set(Eo *obj_id, const Eo *parent_id) { - EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, EINA_FALSE); - if (parent) - EO_MAGIC_RETURN_VAL(parent, EO_EINA_MAGIC, EINA_FALSE); + EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, EINA_FALSE); + if (parent_id) + { + EO_OBJ_POINTER_RETURN_VAL(parent_id, parent, EINA_FALSE); + } - if (obj->parent == parent) - return EINA_TRUE; + if (obj->parent == parent_id) + return EINA_TRUE; _eo_ref(obj); - if (eo_composite_is(obj)) + if (eo_composite_is(obj_id)) { - eo_composite_detach(obj, obj->parent); + eo_composite_detach(obj_id, obj->parent); } if (obj->parent) { - obj->parent->children = - eina_inlist_remove(obj->parent->children, EINA_INLIST_GET(obj)); - eo_xunref(obj, obj->parent); + EO_OBJ_POINTER_RETURN_VAL(obj->parent, obj_parent, EINA_FALSE); + obj_parent->children = eina_list_remove(obj_parent->children, obj_id); + eo_xunref(obj_id, obj->parent); } - obj->parent = (Eo *) parent; + obj->parent = (Eo *) parent_id; if (obj->parent) { - obj->parent->children = - eina_inlist_append(obj->parent->children, EINA_INLIST_GET(obj)); - eo_xref(obj, obj->parent); + EO_OBJ_POINTER_RETURN_VAL(parent_id, parent, EINA_FALSE); + parent->children = eina_list_append(parent->children, obj_id); + eo_xref(obj_id, obj->parent); } _eo_unref(obj); @@ -1085,12 +1134,16 @@ eo_parent_set(Eo *obj, const Eo *parent) } EAPI Eo * -eo_add_internal(const char *file, int line, const Eo_Class *klass, Eo *parent, ...) +eo_add_internal(const char *file, int line, const Eo_Class *klass_id, Eo *parent_id, ...) { Eina_Bool do_err; + _Eo_Class *klass = _eo_class_pointer_get(klass_id); EO_MAGIC_RETURN_VAL(klass, EO_CLASS_EINA_MAGIC, NULL); - if (parent) EO_MAGIC_RETURN_VAL(parent, EO_EINA_MAGIC, NULL); + if (parent_id) + { + EO_OBJ_POINTER_RETURN_VAL(parent_id, parent, NULL); + } if (EINA_UNLIKELY(klass->desc->type != EO_CLASS_TYPE_REGULAR)) { @@ -1098,14 +1151,18 @@ eo_add_internal(const char *file, int line, const Eo_Class *klass, Eo *parent, . return NULL; } - Eo *obj = calloc(1, EO_ALIGN_SIZE(sizeof(*obj)) + + _Eo *obj = calloc(1, EO_ALIGN_SIZE(sizeof(*obj)) + (klass->data_offset + EO_ALIGN_SIZE(klass->desc->data_size)) + klass->extn_data_size); - EINA_MAGIC_SET(obj, EO_EINA_MAGIC); obj->refcount++; obj->klass = klass; - eo_parent_set(obj, parent); +#ifndef HAVE_EO_ID + EINA_MAGIC_SET(obj, EO_EINA_MAGIC); +#endif + Eo_Id obj_id = _eo_id_allocate(obj); + obj->obj_id = obj_id; + eo_parent_set((Eo *)obj_id, parent_id); _eo_condtor_reset(obj); @@ -1114,7 +1171,7 @@ eo_add_internal(const char *file, int line, const Eo_Class *klass, Eo *parent, . /* Run the relevant do stuff. */ { va_list p_list; - va_start(p_list, parent); + va_start(p_list, parent_id); do_err = !_eo_dov_internal(file, line, obj, EO_OP_TYPE_REGULAR, &p_list); va_end(p_list); } @@ -1135,7 +1192,7 @@ eo_add_internal(const char *file, int line, const Eo_Class *klass, Eo *parent, . _eo_unref(obj); - return obj; + return (Eo *)obj_id; fail: /* Unref twice, once for the ref above, and once for the basic object ref. */ @@ -1153,32 +1210,32 @@ typedef struct } Eo_Xref_Node; EAPI Eo * -eo_xref_internal(const char *file, int line, Eo *obj, const Eo *ref_obj) +eo_xref_internal(const char *file, int line, Eo *obj_id, const Eo *ref_obj_id) { - EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, obj); + EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, obj_id); _eo_ref(obj); #ifdef EO_DEBUG Eo_Xref_Node *xref = calloc(1, sizeof(*xref)); - xref->ref_obj = ref_obj; + xref->ref_obj = ref_obj_id; xref->file = file; xref->line = line; obj->xrefs = eina_inlist_prepend(obj->xrefs, EINA_INLIST_GET(xref)); #else - (void) ref_obj; + (void) ref_obj_id; (void) file; (void) line; #endif - return obj; + return obj_id; } EAPI void -eo_xunref(Eo *obj, const Eo *ref_obj) +eo_xunref(Eo *obj_id, const Eo *ref_obj_id) { - EO_MAGIC_RETURN(obj, EO_EINA_MAGIC); + EO_OBJ_POINTER_RETURN(obj_id, obj); #ifdef EO_DEBUG Eo_Xref_Node *xref = NULL; EINA_INLIST_FOREACH(obj->xrefs, xref) @@ -1198,41 +1255,41 @@ eo_xunref(Eo *obj, const Eo *ref_obj) return; } #else - (void) ref_obj; + (void) ref_obj_id; #endif _eo_unref(obj); } -static inline Eo * -_eo_ref(Eo *obj) +static inline _Eo * +_eo_ref(_Eo *obj) { obj->refcount++; return obj; } EAPI Eo * -eo_ref(const Eo *_obj) +eo_ref(const Eo *obj_id) { - Eo *obj = (Eo *) _obj; - EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, obj); + EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, (Eo *)obj_id); - return _eo_ref(obj); + _eo_ref(obj); + return (Eo *)obj_id; } static inline void -_eo_del_internal(const char *file, int line, Eo *obj) +_eo_del_internal(const char *file, int line, _Eo *obj) { Eina_Bool do_err; /* We need that for the event callbacks that may ref/unref. */ obj->refcount++; - eo_do(obj, eo_event_callback_call(EO_EV_DEL, NULL, NULL)); + eo_do((Eo *) obj->obj_id, eo_event_callback_call(EO_EV_DEL, NULL, NULL)); - const Eo_Class *klass = eo_class_get(obj); + const _Eo_Class *klass = obj->klass; _eo_condtor_reset(obj); - do_err = eo_do(obj, eo_destructor()); + do_err = eo_do((Eo *)obj->obj_id, eo_destructor()); if (EINA_UNLIKELY(!do_err)) { ERR("in %s:%d: Object of class '%s' - One of the object destructors have failed.", @@ -1251,13 +1308,13 @@ _eo_del_internal(const char *file, int line, Eo *obj) Eo *emb_obj; EINA_LIST_FOREACH_SAFE(obj->composite_objects, itr, itr_n, emb_obj) { - eo_composite_detach(emb_obj, obj); + eo_composite_detach(emb_obj, (Eo *)obj->obj_id); } } while (obj->children) { - eo_parent_set(EINA_INLIST_CONTAINER_GET(obj->children, Eo), NULL); + eo_parent_set(eina_list_data_get(obj->children), NULL); // ZZZ } obj->del = EINA_TRUE; @@ -1265,14 +1322,14 @@ _eo_del_internal(const char *file, int line, Eo *obj) } static inline void -_eo_free(Eo *obj) +_eo_free(_Eo *obj) { - EINA_MAGIC_SET(obj, EO_FREED_EINA_MAGIC); + _eo_id_release(obj->obj_id); free(obj); } static inline void -_eo_unref(Eo *obj) +_eo_unref(_Eo *obj) { --(obj->refcount); if (obj->refcount == 0) @@ -1309,10 +1366,9 @@ _eo_unref(Eo *obj) } EAPI void -eo_unref(const Eo *_obj) +eo_unref(const Eo *obj_id) { - Eo *obj = (Eo *) _obj; - EO_MAGIC_RETURN(obj, EO_EINA_MAGIC); + EO_OBJ_POINTER_RETURN(obj_id, obj); _eo_unref(obj); } @@ -1325,34 +1381,35 @@ eo_del(const Eo *obj) } EAPI int -eo_ref_get(const Eo *obj) +eo_ref_get(const Eo *obj_id) { - EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, 0); + EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, 0); return obj->refcount; } EAPI Eo * -eo_parent_get(const Eo *obj) +eo_parent_get(const Eo *obj_id) { - EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, NULL); + EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, NULL); return obj->parent; } EAPI void -eo_error_set_internal(const Eo *obj, const char *file, int line) +eo_error_set_internal(const Eo *obj_id, const char *file, int line) { - EO_MAGIC_RETURN(obj, EO_EINA_MAGIC); + EO_OBJ_POINTER_RETURN(obj_id, obj); ERR("Error with obj '%p' at %s:%d", obj, file, line); - ((Eo *) obj)->do_error = EINA_TRUE; + obj->do_error = EINA_TRUE; } void -_eo_condtor_done(Eo *obj) +_eo_condtor_done(Eo *obj_id) { + EO_OBJ_POINTER_RETURN(obj_id, obj); if (obj->condtor_done) { ERR("Object %p is already constructed at this point.", obj); @@ -1363,20 +1420,19 @@ _eo_condtor_done(Eo *obj) } static void -_eo_condtor_reset(Eo *obj) +_eo_condtor_reset(_Eo *obj) { obj->condtor_done = EINA_FALSE; } static inline void * -_eo_data_get(const Eo *obj, const Eo_Class *klass) +_eo_data_get(const _Eo *obj, const _Eo_Class *klass) { if (EINA_LIKELY(klass->desc->data_size > 0)) { if (EINA_UNLIKELY(klass->desc->type == EO_CLASS_TYPE_MIXIN)) { - Eo_Extension_Data_Offset *doff_itr = - eo_class_get(obj)->extn_data_off; + Eo_Extension_Data_Offset *doff_itr = obj->klass->extn_data_off; if (!doff_itr) return NULL; @@ -1398,10 +1454,11 @@ _eo_data_get(const Eo *obj, const Eo_Class *klass) } EAPI void * -eo_data_get(const Eo *obj, const Eo_Class *klass) +eo_data_get(const Eo *obj_id, const Eo_Class *klass_id) { void *ret; - EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, NULL); + EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, NULL); + _Eo_Class *klass = _eo_class_pointer_get(klass_id); EO_MAGIC_RETURN_VAL(klass, EO_CLASS_EINA_MAGIC, NULL); #ifdef EO_DEBUG @@ -1433,7 +1490,7 @@ eo_init(void) eina_init(); - _eo_sz = EO_ALIGN_SIZE(sizeof (Eo)); + _eo_sz = EO_ALIGN_SIZE(sizeof (_Eo)); _eo_classes = NULL; _eo_classes_last_id = EO_CLASS_IDS_FIRST - 1; @@ -1474,7 +1531,7 @@ EAPI Eina_Bool eo_shutdown(void) { size_t i; - Eo_Class **cls_itr = _eo_classes; + _Eo_Class **cls_itr = _eo_classes; if (--_eo_init_count > 0) return EINA_TRUE; @@ -1494,6 +1551,8 @@ eo_shutdown(void) eina_lock_free(&_eo_class_creation_lock); + _eo_free_ids_tables(); + eina_log_domain_unregister(_eo_log_dom); _eo_log_dom = -1; @@ -1502,54 +1561,54 @@ eo_shutdown(void) } EAPI void -eo_composite_attach(Eo *comp_obj, Eo *parent) +eo_composite_attach(Eo *comp_obj_id, Eo *parent_id) { - EO_MAGIC_RETURN(comp_obj, EO_EINA_MAGIC); - EO_MAGIC_RETURN(parent, EO_EINA_MAGIC); + EO_OBJ_POINTER_RETURN(comp_obj_id, comp_obj); + EO_OBJ_POINTER_RETURN(parent_id, parent); comp_obj->composite = EINA_TRUE; - parent->composite_objects = eina_list_prepend(parent->composite_objects, comp_obj); - eo_parent_set(comp_obj, parent); + parent->composite_objects = eina_list_prepend(parent->composite_objects, comp_obj_id); + eo_parent_set(comp_obj_id, parent_id); } EAPI void -eo_composite_detach(Eo *comp_obj, Eo *parent) +eo_composite_detach(Eo *comp_obj_id, Eo *parent_id) { - EO_MAGIC_RETURN(comp_obj, EO_EINA_MAGIC); - EO_MAGIC_RETURN(parent, EO_EINA_MAGIC); + EO_OBJ_POINTER_RETURN(comp_obj_id, comp_obj); + EO_OBJ_POINTER_RETURN(parent_id, parent); comp_obj->composite = EINA_FALSE; - parent->composite_objects = eina_list_remove(parent->composite_objects, comp_obj); - eo_parent_set(comp_obj, NULL); + parent->composite_objects = eina_list_remove(parent->composite_objects, comp_obj_id); + eo_parent_set(comp_obj_id, NULL); } EAPI Eina_Bool -eo_composite_is(const Eo *comp_obj) +eo_composite_is(const Eo *comp_obj_id) { - EO_MAGIC_RETURN_VAL(comp_obj, EO_EINA_MAGIC, EINA_FALSE); + EO_OBJ_POINTER_RETURN_VAL(comp_obj_id, comp_obj, EINA_FALSE); return comp_obj->composite; } EAPI Eina_Bool -eo_destructed_is(const Eo *obj) +eo_destructed_is(const Eo *obj_id) { - EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, EINA_FALSE); + EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, EINA_FALSE); return obj->del; } EAPI void -eo_manual_free_set(Eo *obj, Eina_Bool manual_free) +eo_manual_free_set(Eo *obj_id, Eina_Bool manual_free) { - EO_MAGIC_RETURN(obj, EO_EINA_MAGIC); + EO_OBJ_POINTER_RETURN(obj_id, obj); obj->manual_free = manual_free; } EAPI void -eo_manual_free(Eo *obj) +eo_manual_free(Eo *obj_id) { - EO_MAGIC_RETURN(obj, EO_EINA_MAGIC); + EO_OBJ_POINTER_RETURN(obj_id, obj); if (EINA_FALSE == obj->manual_free) { @@ -1559,7 +1618,7 @@ eo_manual_free(Eo *obj) if (!obj->del) { - ERR("Tried deleting the object %p while still referenced(%d).", obj, eo_ref_get(obj)); + ERR("Tried deleting the object %p while still referenced(%d).", obj_id, obj->refcount); return; } diff --git a/src/lib/eo/eo_private.h b/src/lib/eo/eo_private.h index 0045645701..28666d168a 100644 --- a/src/lib/eo/eo_private.h +++ b/src/lib/eo/eo_private.h @@ -56,4 +56,6 @@ extern int _eo_log_dom; void _eo_condtor_done(Eo *obj); +typedef struct _Eo_Internal _Eo; + #endif diff --git a/src/lib/eo/eo_ptr_indirection.c b/src/lib/eo/eo_ptr_indirection.c new file mode 100644 index 0000000000..a77b8544b9 --- /dev/null +++ b/src/lib/eo/eo_ptr_indirection.c @@ -0,0 +1,282 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "eo_ptr_indirection.h" + +/* Start of pointer indirection: + * + * This feature is responsible of hiding from the developer the real pointer of + * the Eo object to supply a better memory management by preventing bad usage + * of the pointers. + * + * Eo * is no more a pointer but an index to an entry into a ids table. + * For a better memory usage, we don't allocate all the tables at the beginning, + * but only when needed (i.e no more empty entries in allocated tables. + * In addition, tables are composed of intermediate tables, this for memory + * optimizations. Finding the different table, intermediate table and relative + * entry is done by bits manipulation of the id: + * + * id = Table | Inter_table | Entry | Generation + * + * Generation helps finding abuse of ids. When an entry is assigned to an + * object, a generation is inserted into the id. If the developer uses this id + * although the object is freed and another one has replaced it into the same + * entry of the table, the generation will be different and an error will + * occur when accessing with the old id. + * + * Each table is composed of: + * - pointers to the objects + * - generations assigned to the objects + * - a boolean table indicating if an entry is active + * - an index 'start' indicating which entry is the next one to use. + * - a queue that will help us to store the unused entries. It stores only the + * entries that have been used at least one time. The entries that have + * never been used are "pointed" by the start parameter. + * When an entry is searched into a table, we first try to pop from the + * queue. If a NULL value is returned, we have to use one of the entries that + * have never been used. If a such entry doesn't exist, we pass to the next + * table. Otherwise, we reserve this entry to the object pointer and create + * the id with the table id, the intermediate table id, the entry and a + * generation. + * When an object is freed, the entry into the table is released by pushing + * it into the queue. + */ + +#if SIZEOF_UINTPTR_T == 4 +/* 32 bits */ +# define BITS_FOR_IDS_TABLE 8 +# define BITS_FOR_IDS_INTER_TABLE 4 +# define BITS_FOR_ID_IN_TABLE 10 +# define BITS_FOR_GENERATION_COUNTER 10 +#else +/* 64 bits */ +# define BITS_FOR_IDS_TABLE 8 +# define BITS_FOR_IDS_INTER_TABLE 20 +# define BITS_FOR_ID_IN_TABLE 16 +# define BITS_FOR_GENERATION_COUNTER 20 +#endif + +typedef uintptr_t Table_Index; + +/* Shifts macros to manipulate the Eo id */ +#define SHIFT_FOR_IDS_TABLE \ + (BITS_FOR_IDS_INTER_TABLE + BITS_FOR_ID_IN_TABLE + BITS_FOR_GENERATION_COUNTER) + +#define SHIFT_FOR_IDS_INTER_TABLE \ + (BITS_FOR_ID_IN_TABLE + BITS_FOR_GENERATION_COUNTER) + +#define SHIFT_FOR_ID_IN_TABLE (BITS_FOR_GENERATION_COUNTER) + +/* Maximum ranges */ +#define MAX_IDS_TABLES (1 << BITS_FOR_IDS_TABLE) +#define MAX_IDS_INTER_TABLES (1 << BITS_FOR_IDS_INTER_TABLE) +#define MAX_IDS_PER_TABLE (1 << BITS_FOR_ID_IN_TABLE) +#define MAX_GENERATIONS (1 << BITS_FOR_GENERATION_COUNTER) + +/* Table */ +typedef struct +{ + /* Pointers of objects stored in table */ + _Eo *ptrs[MAX_IDS_PER_TABLE]; + /* Generations */ + Table_Index generation[MAX_IDS_PER_TABLE]; + /* Active flags */ + char active[MAX_IDS_PER_TABLE >> 3]; + /* Queue to handle free entries */ + Eina_Trash *queue; + /* Indicates where start the "never used" entries */ + Table_Index start; +} _Eo_Ids_Table; + +/* Tables handling pointers indirection */ +_Eo_Ids_Table **_eo_ids_tables[MAX_IDS_TABLES] = { NULL }; + +/* Next generation to use when assigning a new entry to a Eo pointer */ +Table_Index _eo_generation_counter; + +/* Internal macro for active flag manipulation */ +#define _ENTRY_ACTIVE_DO_OP(table, id_in_table, op) \ + (table)->active[(id_in_table) >> 3] op (1 << ((id_in_table) % 8)) + +/* Macro that indicates if an entry is active */ +#define IS_ENTRY_ACTIVE(table, id_in_table) \ + (_ENTRY_ACTIVE_DO_OP(table, id_in_table, &)) +/* Macro that activates an entry */ +#define ACTIVATE_ENTRY(table, id_in_table) \ + _ENTRY_ACTIVE_DO_OP(table, id_in_table, |=) +/* Macro that de-activates an entry */ +#define DEACTIVATE_ENTRY(table, id_in_table) \ + _ENTRY_ACTIVE_DO_OP(table, id_in_table, &=~) + +/* Macro used to compose an Eo id */ +#define EO_COMPOSE_ID(TABLE, INTER_TABLE, ENTRY, GENERATION) \ + (Eo_Id)(((TABLE & (MAX_IDS_TABLES - 1)) << SHIFT_FOR_IDS_TABLE) | \ + ((INTER_TABLE & (MAX_IDS_INTER_TABLES - 1)) << SHIFT_FOR_IDS_INTER_TABLE) |\ + ((ENTRY & (MAX_IDS_PER_TABLE - 1)) << SHIFT_FOR_ID_IN_TABLE) | \ + (GENERATION & (MAX_GENERATIONS - 1) )) + +/* Macro to extract from an Eo id the indexes of the tables */ +#define EO_DECOMPOSE_ID(ID, TABLE, INTER_TABLE, ENTRY, GENERATION) \ + TABLE = (ID >> SHIFT_FOR_IDS_TABLE) & (MAX_IDS_TABLES - 1); \ + INTER_TABLE = (ID >> SHIFT_FOR_IDS_INTER_TABLE) & (MAX_IDS_INTER_TABLES - 1); \ + ENTRY = (ID >> SHIFT_FOR_ID_IN_TABLE) & (MAX_IDS_PER_TABLE - 1); \ + GENERATION = ID & (MAX_GENERATIONS - 1); \ + +/* Macro used for readability */ +#define ID_TABLE _eo_ids_tables[table_id][int_table_id] + +_Eo * +_eo_obj_pointer_get(const Eo_Id obj_id) +{ +#ifdef HAVE_EO_ID + Table_Index table_id, int_table_id, entry_id, generation; + + EO_DECOMPOSE_ID((Table_Index) obj_id, table_id, int_table_id, entry_id, generation); + + /* Checking the validity of the entry */ + if (_eo_ids_tables[table_id] && ID_TABLE && IS_ENTRY_ACTIVE(ID_TABLE, entry_id) && + ID_TABLE->generation[entry_id] == generation) + return ID_TABLE->ptrs[entry_id]; + + ERR("obj_id %p is not pointing to a valid object. Maybe it has already been freed.", + (void *)obj_id); + + return NULL; +#else + return (_Eo *)obj_id; +#endif +} + +Eo_Id +_eo_id_allocate(const _Eo *obj) +{ +#ifdef HAVE_EO_ID + Eo_Id ret = 0; + for (Table_Index table_id = 1; table_id < MAX_IDS_TABLES; table_id++) + { + if (!_eo_ids_tables[table_id]) + { + /* We allocate a new table */ + _eo_ids_tables[table_id] = calloc(MAX_IDS_INTER_TABLES, sizeof(_Eo_Ids_Table*)); + } + for (Table_Index int_table_id = 0; int_table_id < MAX_IDS_INTER_TABLES; int_table_id++) + { + _Eo **ptr; + if (!ID_TABLE) + { + /* We allocate a new intermediate table */ + ID_TABLE = calloc(1, sizeof(_Eo_Ids_Table)); + eina_trash_init(&(ID_TABLE->queue)); + /* We select directly the first entry of the new table */ + ptr = &(ID_TABLE->ptrs[0]); + ID_TABLE->start = 1; + } + else + { + /* We try to pop from the queue an unused entry */ + ptr = (_Eo **)eina_trash_pop(&(ID_TABLE->queue)); + } + + if (!ptr && ID_TABLE->start < MAX_IDS_PER_TABLE) + { + /* No more unused entries in the trash but still empty entries in the table */ + ptr = &(ID_TABLE->ptrs[ID_TABLE->start]); + ID_TABLE->start++; + } + + if (ptr) + { + /* An entry was found - need to find the entry id and fill it */ + Table_Index id = ptr - ID_TABLE->ptrs; + ID_TABLE->generation[id] = _eo_generation_counter; + ACTIVATE_ENTRY(ID_TABLE, id); + *ptr = (_Eo *)obj; + ret = EO_COMPOSE_ID(table_id, int_table_id, id, _eo_generation_counter); + _eo_generation_counter++; + _eo_generation_counter %= MAX_GENERATIONS; + return ret; + } + } + } + return ret; +#else + return (Eo_Id)obj; +#endif +} + +void +_eo_id_release(const Eo_Id obj_id) +{ +#ifdef HAVE_EO_ID + Table_Index table_id, int_table_id, entry_id, generation; + EO_DECOMPOSE_ID((Table_Index) obj_id, table_id, int_table_id, entry_id, generation); + + /* Checking the validity of the entry */ + if (!_eo_ids_tables[table_id]) goto error; + if (!ID_TABLE) goto error; + if (ID_TABLE->generation[entry_id] != generation) goto error; + + /* Disable the entry */ + DEACTIVATE_ENTRY(ID_TABLE, entry_id); + /* Push the entry into the queue */ + eina_trash_push(&(ID_TABLE->queue), &(ID_TABLE->ptrs[entry_id])); + + return; + +error: + ERR("obj_id %p is not pointing to a valid object. Maybe it has already been freed.", (void *)obj_id); +#else + (void) obj_id; +#endif +} + +void +_eo_free_ids_tables() +{ + for (Table_Index table_id = 0; table_id < MAX_IDS_TABLES; table_id++) + { + if (_eo_ids_tables[table_id]) + { + for (Table_Index int_table_id = 0; int_table_id < MAX_IDS_INTER_TABLES; int_table_id++) + { + if (ID_TABLE) + { + free(ID_TABLE); + } + } + free(_eo_ids_tables[table_id]); + } + _eo_ids_tables[table_id] = NULL; + } +} + +#ifdef EFL_DEBUG +void +_eo_print() +{ + unsigned long obj_number = 0; + for (Table_Index table_id = 0; table_id < MAX_IDS_TABLES; table_id++) + { + if (_eo_ids_tables[table_id]) + { + for (Table_Index int_table_id = 0; int_table_id < MAX_IDS_INTER_TABLES; int_table_id++) + { + if (ID_TABLE) + { + for (Table_Index entry_id = 0; entry_id < MAX_IDS_PER_TABLE; entry_id++) + { + if (IS_ENTRY_ACTIVE(ID_TABLE, entry_id)) + { + printf("%ld: %p -> (%p, %p, %p, %p)\n", obj_number++, + ID_TABLE->ptrs[entry_id], + (void *)table_id, (void *)int_table_id, (void *)entry_id, + (void *)ID_TABLE->generation[entry_id]); + } + } + } + } + } + } +} +#endif diff --git a/src/lib/eo/eo_ptr_indirection.h b/src/lib/eo/eo_ptr_indirection.h new file mode 100644 index 0000000000..86355b3fb7 --- /dev/null +++ b/src/lib/eo/eo_ptr_indirection.h @@ -0,0 +1,62 @@ +#ifndef EO_PTR_INDIRECTION_H +#define EO_PTR_INDIRECTION_H + +#include "Eo.h" +#include "eo_private.h" + +typedef size_t Eo_Id; + +/* Retrieves the pointer to the object from the id */ +_Eo *_eo_obj_pointer_get(const Eo_Id obj_id); + +/* Allocates an entry for the given object */ +Eo_Id _eo_id_allocate(const _Eo *obj); + +/* Releases an entry by the object id */ +void _eo_id_release(const Eo_Id obj_id); + +/* Free all the entries and the tables */ +void _eo_free_ids_tables(); + +/* Macro used to obtain the object pointer and return if fails. */ + +#ifdef HAVE_EO_ID + +#define EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, ret) \ + _Eo *obj; \ + do { \ + obj = _eo_obj_pointer_get((Eo_Id)obj_id); \ + if (!obj) return ret; \ + } while (0) + +#define EO_OBJ_POINTER_RETURN(obj_id, obj) \ + _Eo *obj; \ + do { \ + obj = _eo_obj_pointer_get((Eo_Id)obj_id); \ + if (!obj) return; \ + } while (0) + +#else + +#define EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, ret) \ + _Eo *obj; \ + do { \ + obj = _eo_obj_pointer_get(obj_id); \ + EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, ret); \ + } while (0) + +#define EO_OBJ_POINTER_RETURN(obj_id, obj) \ + _Eo *obj; \ + do { \ + obj = _eo_obj_pointer_get(obj_id); \ + EO_MAGIC_RETURN(obj, EO_EINA_MAGIC); \ + } while (0) + +#endif + +#ifdef EFL_DEBUG +void _eo_print(); +#endif + +#endif +