eina: add Eina_Object API.

This API is what could be used by all EFL library for their exposed
type (Evas_Object, Ecore_Timer, Ecore_Animator, Eio_File, ...). The
purpose of Eina_Object is to provide an "obscure" pointer that is
infact an ID with a generation count that will never be dereferenced
directly.
   This provide the benefit of always accessing a living object
with 1/256 chance to being the expected generation of it, that will
always be of the right type.
   It also provide asynchronous repacking ability (still highly
inefficient, but not really hard to improve), simple inheritance
with constructor/destructor and link between object.

All this implementation is highly open for comment, idea, review,
fix and change. I didn't got the time to write a sample test right
now. Maybe will come tomorrow. Same for docs.



SVN revision: 58562
This commit is contained in:
Cedric BAIL 2011-04-11 18:00:34 +00:00
parent 6ffb3b8d9f
commit 8b276b36c7
5 changed files with 1031 additions and 2 deletions

View File

@ -46,3 +46,4 @@
* Add eina_inlist_sort.
* Add eina_mempool_repack.
* Add Eina_Object API.

View File

@ -53,7 +53,8 @@ eina_strbuf.h \
eina_ustrbuf.h \
eina_unicode.h \
eina_quadtree.h \
eina_simple_xml_parser.h
eina_simple_xml_parser.h \
eina_object.h
installed_mainheaderdir = $(includedir)/eina-@VMAJ@
dist_installed_mainheader_DATA = Eina.h eina_config.h

View File

@ -0,0 +1,79 @@
/* EINA - EFL data type library
* Copyright (C) 2011 Cedric Bail
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library;
* if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef EINA_OBJECT_H__
#define EINA_OBJECT_H__
#include "eina_config.h"
#include "eina_types.h"
/**
* @addtogroup Eina_Object Object
*
* @brief These functions manage object providing pointer checking
* and memory repacking.
*
* Each Eina_Object is in fact only an ID and a generation count. This
* make it possible to check if the ID is allocated by checking that it
* is inside the boudary limit of the allocated range. The generation
* count, give the possibility to check that we use a valid alive pointer
* as generation is increased each time an object is allocated/destroyed.
* And finally it provide type checking against Eina_Class.
*
* It is also to define link between object, then when father get deleted
* all child will get deleted and their respective destructor will be called.
*
* @{
*/
typedef struct _Eina_Class Eina_Class;
typedef struct _Eina_Object Eina_Object;
typedef void (*Eina_Class_Callback)(Eina_Class *class,
void *object,
void *data);
Eina_Class *eina_class_new(const char *name,
unsigned int class_size,
unsigned int pool_size,
Eina_Class_Callback constructor,
Eina_Class_Callback destructor,
Eina_Class *parent,
void *data);
const char *eina_class_name_get(Eina_Class *class);
unsigned int eina_class_size_get(Eina_Class *class);
unsigned int eina_class_object_size_get(Eina_Class *class);
void eina_class_del(Eina_Class *class);
void eina_class_repack(Eina_Class *class);
Eina_Object *eina_object_add(Eina_Class *class);
void *eina_object_pointer_get(Eina_Class *class,
Eina_Object *object);
void eina_object_del(Eina_Class *class,
Eina_Object *object);
Eina_Bool eina_object_parent_set(Eina_Class *parent_class, Eina_Object *parent,
Eina_Class *object_class, Eina_Object *object);
Eina_Object *eina_object_parent_get(Eina_Class *class, Eina_Object *object);
/**
* @}
*/
#endif

View File

@ -46,7 +46,8 @@ eina_unicode.c \
eina_ustrbuf.c \
eina_ustringshare.c \
eina_value.c \
eina_simple_xml_parser.c
eina_simple_xml_parser.c \
eina_object.c
if EINA_HAVE_WIN32
base_sources += eina_file_win32.c

View File

@ -0,0 +1,947 @@
/* EINA - EFL data type library
* Copyright (C) 2011 Cedric Bail
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library;
* if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <string.h>
#ifdef EFL_HAVE_POSIX_THREADS
#include <pthread.h>
# ifdef EFL_DEBUG_THREADS
# include <assert.h>
# endif
#endif
#ifdef EFL_HAVE_WIN32_THREADS
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
# undef WIN32_LEAN_AND_MEAN
#endif
#include "eina_object.h"
#include "eina_private.h"
#include "eina_inlist.h"
#include "eina_rbtree.h"
#include "eina_mempool.h"
#include "eina_trash.h"
#include "eina_log.h"
#include "eina_stringshare.h"
/*============================================================================*
* Local *
*============================================================================*/
/**
* @cond LOCAL
*/
/* If we are on a 64bits computer user bigger generation and ID */
/* FIXME: make it GCC independant */
/* FIXME: maybe having 2^32 objects doesn't make sense and 2^24 are enough
so instead of increasing the object count, we could just add a magic
to first check if the pointer is valid at all (and maybe use a pointer
that will always trigger a segv if we try to use it directly).
*/
#ifdef _LP64
typedef unsigned long Eina_Object_ID;
typedef unsigned short Eina_Object_Generation;
#define EINA_GEN_OFFSET 48
#else
typedef unsigned int Eina_Object_ID;
typedef unsigned char Eina_Object_Generation;
#define EINA_GEN_OFFSET 24
#endif
typedef struct _Eina_Class_Range Eina_Class_Range;
typedef struct _Eina_Object_Item Eina_Object_Item;
typedef struct _Eina_Range Eina_Range;
typedef struct _Eina_Class_Top Eina_Class_Top;
struct _Eina_Range
{
EINA_INLIST;
unsigned int start;
unsigned int end;
};
struct _Eina_Object_Item
{
EINA_INLIST;
Eina_Class_Range *range;
Eina_Object_Item *parent;
Eina_Inlist *link;
unsigned int index;
};
struct _Eina_Class_Range
{
EINA_INLIST;
EINA_RBTREE;
unsigned int start;
unsigned int end;
unsigned int current;
unsigned int empty_count;
Eina_Class *type;
Eina_Trash *empty;
Eina_Object_Item **pointer_array;
Eina_Object_Generation generation_array[1];
};
struct _Eina_Class_Top
{
Eina_Class *top_parent;
Eina_Rbtree *range;
Eina_Inlist *available;
unsigned int upper_limit;
};
struct _Eina_Class
{
EINA_INLIST;
const char *name;
Eina_Class_Top *top;
Eina_Class *parent;
Eina_Inlist *childs;
Eina_Class_Callback constructor;
Eina_Class_Callback destructor;
void *data;
Eina_Inlist *allocated_range;
Eina_Mempool *mempool;
unsigned int class_size;
unsigned int object_size;
unsigned int pool_size;
Eina_Bool repack_needed : 1;
#ifdef EFL_HAVE_THREADS
# ifdef EFL_HAVE_POSIX_THREADS
# ifdef EFL_DEBUG_THREADS
pthread_t self;
# endif
pthread_mutex_t mutex;
# else
HANDLE mutex;
# endif
#endif
EINA_MAGIC;
};
static const char EINA_MAGIC_CLASS_STR[] = "Eina Class";
static Eina_Mempool *_eina_class_mp = NULL;
static Eina_Mempool *_eina_top_mp = NULL;
static Eina_Mempool *_eina_range_mp = NULL;
static int _eina_object_log_dom = -1;
static unsigned int _eina_object_item_size = 0;
#ifdef ERR
#undef ERR
#endif
#define ERR(...) EINA_LOG_DOM_ERR(_eina_object_log_dom, __VA_ARGS__)
#ifdef DBG
#undef DBG
#endif
#define DBG(...) EINA_LOG_DOM_DBG(_eina_object_log_dom, __VA_ARGS__)
#define EINA_MAGIC_CHECK_CLASS(d, ...) \
do { \
if (!EINA_MAGIC_CHECK(d, EINA_MAGIC_CLASS)) \
{ \
EINA_MAGIC_FAIL(d, EINA_MAGIC_CLASS); \
return __VA_ARGS__; \
} \
} while(0)
static int
_eina_rbtree_cmp_range(const Eina_Rbtree *node, const void *key,
__UNUSED__ int length, __UNUSED__ void *data)
{
Eina_Class_Range *range;
Eina_Object_ID id;
range = EINA_RBTREE_CONTAINER_GET(node, Eina_Class_Range);
id = (Eina_Object_ID) key;
if (id < range->start) return -1;
else if (id >= range->end) return 1;
return 0;
}
static Eina_Rbtree_Direction
_eina_class_direction_range(const Eina_Rbtree *left,
const Eina_Rbtree *right,
__UNUSED__ void *data)
{
Eina_Class_Range *rl;
Eina_Class_Range *rr;
rl = EINA_RBTREE_CONTAINER_GET(left, Eina_Class_Range);
rr = EINA_RBTREE_CONTAINER_GET(right, Eina_Class_Range);
if (rl->start < rr->start) return EINA_RBTREE_LEFT;
return EINA_RBTREE_RIGHT;
}
/* really destroying a range and handling that case is a complex
problem to solve. Not handling it right now, exposing myself to
DoS. */
static void
_eina_range_cleanup(Eina_Class_Range *range)
{
range->current = 0;
range->empty = NULL;
}
static void
_eina_object_constructor_call(Eina_Class *class, void *object)
{
if (class->parent) _eina_object_constructor_call(class->parent, object);
if (class->constructor) class->constructor(class, object, class->data);
}
static void
_eina_object_destructor_call(Eina_Class *class, void *object)
{
if (class->destructor) class->destructor(class, object, class->data);
if (class->parent) _eina_object_destructor_call(class->parent, object);
}
static Eina_Object*
_eina_object_get(Eina_Object_Item *item)
{
Eina_Object_Generation gen;
Eina_Object_ID id;
if (!item) return NULL;
gen = item->range->generation_array[item->index];
id = (gen << EINA_GEN_OFFSET) + item->range->start + item->index;
return (Eina_Object *) id;
}
static Eina_Object_Item *
_eina_object_find_item(Eina_Class *class, Eina_Object *object)
{
Eina_Class_Range *matched;
Eina_Object_Item *item;
Eina_Class *search;
Eina_Rbtree *match;
Eina_Object_Generation generation;
Eina_Object_ID id;
int idx;
id = (Eina_Object_ID) object;
idx = id & ((1 << EINA_GEN_OFFSET) - 1);
generation = id & !((1 << EINA_GEN_OFFSET) - 1);
/* Try to find the ID */
match = eina_rbtree_inline_lookup(class->top->range,
(void*) idx, sizeof (Eina_Object_ID),
_eina_rbtree_cmp_range, NULL);
/* ID not found, invalid pointer ! */
if (!match)
{
ERR("%p: ID [%i] not found in class hiearchy of [%s].",
object, idx, class->name);
return NULL;
}
matched = EINA_RBTREE_CONTAINER_GET(match, Eina_Class_Range);
/* generation mismatch, invalid pointer ! */
if (generation != matched->generation_array[idx - matched->start])
{
ERR("%p: generation mismatch [%i] vs [%i].",
object, generation, matched->generation_array[idx - matched->start]);
return NULL;
}
/* does it belong to the right class ? */
for (search = matched->type; search && search != class; search = search->parent)
;
/* class match request or invalid pointer ! */
if (search != class)
{
ERR("%p: from class [%s] is not in the hierarchie of [%s].",
object, matched->type->name, class->name);
return NULL;
}
/* retrieve pointer */
item = matched->pointer_array[id - matched->start];
/* allocated or invalid pointer ? */
if (!item)
{
ERR("%p: ID is not allocated.", object);
return NULL;
}
/* be aware, that because we use eina_trash to store empty pointer after first use,
pointer could be != NULL and still be empty. Need another pool of data somewhere
to store the state of the allocation... Is it needed ?
*/
return item;
}
static void
_eina_object_item_del(Eina_Object_Item *item)
{
Eina_Class *class;
class = item->range->type;
_eina_object_destructor_call(class,
(unsigned char*) item + _eina_object_item_size);
eina_trash_push(&item->range->empty, item->range->pointer_array + item->index);
item->range->generation_array[item->index]++;
item->range->empty_count++;
if (item->range->empty_count == item->range->end - item->range->start)
_eina_range_cleanup(item->range);
item->range = NULL;
if (item->parent)
item->parent->link = eina_inlist_remove(item->parent->link, EINA_INLIST_GET(item));
item->parent = NULL;
while (item->link)
{
Eina_Object_Item *child;
child = EINA_INLIST_CONTAINER_GET(item->link, Eina_Object_Item);
_eina_object_item_del(child);
}
eina_mempool_free(class->mempool, item);
}
static Eina_Class_Range *
_eina_class_empty_range_get(Eina_Inlist *list)
{
while (list)
{
Eina_Class_Range *range;
range = EINA_INLIST_CONTAINER_GET(list, Eina_Class_Range);
if (range->empty_count > 0)
return range;
list = list->next;
}
return NULL;
}
static Eina_Class_Range *
_eina_class_range_add(Eina_Class *class)
{
Eina_Class_Range *range;
unsigned char *tmp;
Eina_Range *av = NULL;
range = malloc(sizeof (Eina_Class_Range)
+ sizeof (Eina_Object_Item*) * class->pool_size
+ sizeof (Eina_Object_Generation) * (class->pool_size - 1));
if (!range) return NULL;
tmp = (void*) (range + 1);
tmp += sizeof (Eina_Object_Generation) * (class->pool_size - 1);
range->pointer_array = (Eina_Object_Item**) tmp;
/* no need to fix generation to a specific value as random value should be just fine */
memset(range->pointer_array, 0, sizeof (Eina_Object_Item*) * class->pool_size);
range->current = 0;
range->type = class;
range->empty = NULL;
/* and now find an empty block */
EINA_INLIST_FOREACH(class->top->available, av)
if (av->end - av->start == class->pool_size)
break;
if (av)
{
range->start = av->start;
range->end = av->end;
class->top->available = eina_inlist_remove(class->top->available,
EINA_INLIST_GET(av));
eina_mempool_free(_eina_range_mp, av);
}
else
{
range->start = class->top->upper_limit;
range->end = range->start + class->pool_size;
class->top->upper_limit = range->end;
}
return range;
}
static void
_eina_class_range_del(Eina_Class_Range *range)
{
Eina_Class_Top *top;
Eina_Range *keep;
keep = eina_mempool_malloc(_eina_range_mp, sizeof (Eina_Range));
if (!keep)
{
ERR("Not enougth memory to keep track of allocated range.");
goto delete_class_range;
}
keep->start = range->start;
keep->end = range->end;
top = range->type->top;
top->available = eina_inlist_prepend(top->available,
EINA_INLIST_GET(keep));
delete_class_range:
top->range = eina_rbtree_inline_remove(top->range, EINA_RBTREE_GET(range),
_eina_class_direction_range, NULL);
range->type->allocated_range = eina_inlist_remove(range->type->allocated_range,
EINA_INLIST_GET(range));
free(range);
}
static void
_eina_class_range_repack(void *dst, void *src, void *data)
{
Eina_Object_Item *di = dst;
Eina_Object_Item *si = src;
Eina_Class *class = data;
(void) class;
si->range->pointer_array[si->index] = di;
/* FIXME: We could just lock the right Eina_Class_Range
here instead of locking all the Class */
}
/**
* @}
*/
Eina_Bool
eina_object_init(void)
{
_eina_object_log_dom = eina_log_domain_register("eina_object",
EINA_LOG_COLOR_DEFAULT);
if (_eina_object_log_dom < 0)
{
EINA_LOG_ERR("Could not register log domain: eina_list");
return EINA_FALSE;
}
_eina_class_mp = eina_mempool_add("chained_mempool", "class",
NULL, sizeof (Eina_Class), 64);
if (!_eina_class_mp)
{
ERR("ERROR: Mempool for Eina_Class cannot be allocated in object init.");
goto on_init_fail;
}
_eina_top_mp = eina_mempool_add("chained_mempool", "top",
NULL, sizeof (Eina_Class_Top), 64);
if (!_eina_top_mp)
{
ERR("ERROR: Mempool for Eina_Class_Top cannot be allocated in object init.");
goto on_init_fail;
}
_eina_range_mp = eina_mempool_add("chained_mempool", "range",
NULL, sizeof (Eina_Range), 64);
if (!_eina_range_mp)
{
ERR("ERROR: Mempool for Eina_Class_Top cannot be allocated in object init.");
goto on_init_fail;
}
#define EMS(n) eina_magic_string_static_set(n, n ## _STR)
EMS(EINA_MAGIC_CLASS);
#undef EMS
_eina_object_item_size = eina_mempool_alignof(sizeof (Eina_Object_Item));
return EINA_TRUE;
on_init_fail:
eina_log_domain_unregister(_eina_object_log_dom);
_eina_object_log_dom = -1;
if (_eina_top_mp)
{
eina_mempool_del(_eina_top_mp);
_eina_top_mp = NULL;
}
if (_eina_class_mp)
{
eina_mempool_del(_eina_class_mp);
_eina_class_mp = NULL;
}
return EINA_FALSE;
}
Eina_Bool
eina_object_shutdown(void)
{
eina_mempool_del(_eina_class_mp);
eina_mempool_del(_eina_top_mp);
eina_log_domain_unregister(_eina_object_log_dom);
_eina_object_log_dom = -1;
return EINA_TRUE;
}
Eina_Class *
eina_class_new(const char *name,
unsigned int class_size,
unsigned int pool_size,
Eina_Class_Callback constructor,
Eina_Class_Callback destructor,
Eina_Class *parent,
void *data)
{
Eina_Class *c;
unsigned int object_size = class_size;
if (parent) EINA_MAGIC_CHECK_CLASS(parent, NULL);
c = eina_mempool_malloc(_eina_class_mp, sizeof (Eina_Class));
if (!c) return NULL;
c->parent = parent;
if (parent)
{
parent->childs = eina_inlist_append(parent->childs,
EINA_INLIST_GET(c));
c->top = parent->top;
}
else
{
c->top = eina_mempool_malloc(_eina_top_mp, sizeof (Eina_Class_Top));
c->top->top_parent = c;
c->top->range = NULL;
c->top->available = NULL;
c->top->upper_limit = 0;
}
/* Build complete object size and find top parent */
if (parent) object_size += parent->object_size;
c->name = eina_stringshare_add(name);
c->class_size = class_size;
c->pool_size = pool_size;
c->object_size = object_size;
c->mempool = eina_mempool_add("chained_mempool", "range",
NULL,
_eina_object_item_size + object_size, pool_size);
c->constructor = constructor;
c->destructor = destructor;
c->data = data;
c->allocated_range = NULL;
c->childs = NULL;
#ifdef EFL_HAVE_THREADS
# ifdef EFL_HAVE_POSIX_THREADS
# ifdef EFL_DEBUG_THREADS
c->self = pthread_self();
# endif
pthread_mutex_init(&c->mutex, NULL);
# else
c->mutex = CreateMutex(NULL, FALSE, NULL);
# endif
#endif
EINA_MAGIC_SET(c, EINA_MAGIC_CLASS);
return c;
}
const char *
eina_class_name_get(Eina_Class *class)
{
EINA_MAGIC_CHECK_CLASS(class, NULL);
return class->name;
}
unsigned int
eina_class_size_get(Eina_Class *class)
{
EINA_MAGIC_CHECK_CLASS(class, 0);
return class->class_size;
}
unsigned int
eina_class_object_size_get(Eina_Class *class)
{
EINA_MAGIC_CHECK_CLASS(class, 0);
return class->object_size;
}
void
eina_class_del(Eina_Class *class)
{
EINA_MAGIC_CHECK_CLASS(class);
EINA_MAGIC_SET(class, 0);
while (class->allocated_range)
_eina_class_range_del(EINA_INLIST_CONTAINER_GET(class->allocated_range,
Eina_Class_Range));
while (class->childs)
{
Eina_Class *child;
child = EINA_INLIST_CONTAINER_GET(class->childs, Eina_Class);
eina_class_del(child);
}
if (class->parent)
{
class->parent->childs = eina_inlist_remove(class->parent->childs,
EINA_INLIST_GET(class));
}
else
{
while (class->top->available)
{
Eina_Range *range;
range = EINA_INLIST_CONTAINER_GET(class->top->available, Eina_Range);
class->top->available = eina_inlist_remove(class->top->available,
class->top->available);
eina_mempool_free(_eina_range_mp, range);
}
}
#ifdef EFL_HAVE_THREADS
# ifdef EFL_HAVE_POSIX_THREADS
# ifdef EFL_DEBUG_THREADS
assert(pthread_equal(class->self, pthread_self()));
# endif
pthread_mutex_destroy(&class->mutex);
# else
CloseHandle(class->mutex);
# endif
#endif
eina_mempool_del(class->mempool);
eina_mempool_free(_eina_class_mp, class);
}
void
eina_class_repack(Eina_Class *class)
{
Eina_Class *child;
EINA_MAGIC_CHECK_CLASS(class);
#ifdef EFL_HAVE_THREADS
if (_threads_activated)
{
# ifdef EFL_HAVE_POSIX_THREADS
pthread_mutex_lock(&class->mutex);
# else
WaitForSingleObject(class->mutex, INFINITE);
# endif
}
#ifdef EFL_DEBUG_THREADS
else
assert(pthread_equal(class->self, pthread_self()));
#endif
#endif
eina_mempool_repack(class->mempool, _eina_class_range_repack, class);
#ifdef EFL_HAVE_THREADS
if (_threads_activated)
{
# ifdef EFL_HAVE_POSIX_THREADS
pthread_mutex_unlock(&class->mutex);
# else
ReleaseMutex(class->mutex);
# endif
}
#endif
EINA_INLIST_FOREACH(class->childs, child)
eina_class_repack(child);
}
Eina_Object *
eina_object_add(Eina_Class *class)
{
Eina_Class_Range *range;
Eina_Object_Item **object;
int localid;
EINA_MAGIC_CHECK_CLASS(class, NULL);
/* No need to lock the class as we don't access/modify the pointer inside
* this function. */
range = _eina_class_empty_range_get(class->allocated_range);
if (!range) range = _eina_class_range_add(class);
if (range->empty_count == 0)
{
ERR("The impossible happen, range is empty when it should not !");
return NULL;
}
range->empty_count--;
object = eina_trash_pop(&range->empty);
if (!object) object = range->pointer_array + range->current++;
localid = object - range->pointer_array;
*object = eina_mempool_malloc(class->mempool,
class->object_size + _eina_object_item_size);
(*object)->index = localid;
(*object)->link = NULL;
(*object)->range = range;
_eina_object_constructor_call(class,
((unsigned char*)(*object)) + _eina_object_item_size);
if (!(++range->generation_array[localid]))
++range->generation_array[localid];
return _eina_object_get(*object);
}
void *
eina_object_pointer_get(Eina_Class *class,
Eina_Object *object)
{
Eina_Object_Item *item;
unsigned char *mem = NULL;
if (!object) return NULL;
EINA_MAGIC_CHECK_CLASS(class, NULL);
#ifdef EFL_HAVE_THREADS
if (_threads_activated)
{
# ifdef EFL_HAVE_POSIX_THREADS
pthread_mutex_lock(&class->mutex);
# else
WaitForSingleObject(class->mutex, INFINITE);
# endif
}
#ifdef EFL_DEBUG_THREADS
else
assert(pthread_equal(class->self, pthread_self()));
#endif
#endif
item = _eina_object_find_item(class, object);
if (!item) goto on_error;
mem = (unsigned char*) item + _eina_object_item_size;
on_error:
#ifdef EFL_HAVE_THREADS
if (_threads_activated)
{
# ifdef EFL_HAVE_POSIX_THREADS
pthread_mutex_unlock(&class->mutex);
# else
ReleaseMutex(class->mutex);
# endif
}
#endif
return mem;
}
void
eina_object_del(Eina_Class *class,
Eina_Object *object)
{
Eina_Object_Item *item;
if (!object) return ;
EINA_MAGIC_CHECK_CLASS(class);
#ifdef EFL_HAVE_THREADS
if (_threads_activated)
{
# ifdef EFL_HAVE_POSIX_THREADS
pthread_mutex_lock(&class->mutex);
# else
WaitForSingleObject(class->mutex, INFINITE);
# endif
}
#ifdef EFL_DEBUG_THREADS
else
assert(pthread_equal(class->self, pthread_self()));
#endif
#endif
item = _eina_object_find_item(class, object);
if (!item) goto on_error;
_eina_object_item_del(item);
on_error:
#ifdef EFL_HAVE_THREADS
if (_threads_activated)
{
# ifdef EFL_HAVE_POSIX_THREADS
pthread_mutex_unlock(&class->mutex);
# else
ReleaseMutex(class->mutex);
# endif
}
#endif
}
Eina_Bool
eina_object_parent_set(Eina_Class *parent_class, Eina_Object *parent,
Eina_Class *object_class, Eina_Object *object)
{
Eina_Object_Item *parent_item;
Eina_Object_Item *object_item;
if (!parent) return EINA_FALSE;
if (!object) return EINA_FALSE;
EINA_MAGIC_CHECK_CLASS(parent_class, EINA_FALSE);
EINA_MAGIC_CHECK_CLASS(object_class, EINA_FALSE);
#ifdef EFL_HAVE_THREADS
if (_threads_activated)
{
# ifdef EFL_HAVE_POSIX_THREADS
pthread_mutex_lock(&parent_class->mutex);
pthread_mutex_lock(&object_class->mutex);
# else
WaitForSingleObject(parent_class->mutex, INFINITE);
WaitForSingleObject(object_class->mutex, INFINITE);
# endif
}
#ifdef EFL_DEBUG_THREADS
else
{
assert(pthread_equal(object_class->self, pthread_self()));
assert(pthread_equal(parent_class->self, pthread_self()));
}
#endif
#endif
parent_item = _eina_object_find_item(parent_class, parent);
if (!parent_item) return EINA_FALSE;
object_item = _eina_object_find_item(object_class, object);
if (!object_item) return EINA_FALSE;
if (object_item->parent)
object_item->parent->link = eina_inlist_remove(object_item->parent->link,
EINA_INLIST_GET(object_item));
object_item->parent = parent_item;
parent_item->link = eina_inlist_append(parent_item->link,
EINA_INLIST_GET(object_item));
#ifdef EFL_HAVE_THREADS
if (_threads_activated)
{
# ifdef EFL_HAVE_POSIX_THREADS
pthread_mutex_unlock(&parent_class->mutex);
pthread_mutex_unlock(&object_class->mutex);
# else
ReleaseMutex(parent_class->mutex);
ReleaseMutex(object_class->mutex);
# endif
}
#endif
return EINA_TRUE;
}
Eina_Object *
eina_object_parent_get(Eina_Class *class, Eina_Object *object)
{
Eina_Object_Item *object_item;
if (!object) return EINA_FALSE;
EINA_MAGIC_CHECK_CLASS(class, EINA_FALSE);
#ifdef EFL_HAVE_THREADS
if (_threads_activated)
{
# ifdef EFL_HAVE_POSIX_THREADS
pthread_mutex_lock(&class->mutex);
# else
WaitForSingleObject(class->mutex, INFINITE);
# endif
}
#ifdef EFL_DEBUG_THREADS
else
assert(pthread_equal(class->self, pthread_self()));
#endif
#endif
object_item = _eina_object_find_item(class, object);
if (!object_item) return EINA_FALSE;
return _eina_object_get(object_item->parent);
}