EFL 1.7 svn doobies
[profile/ivi/eina.git] / src / lib / eina_object.c
1 /* EINA - EFL data type library
2  * Copyright (C) 2011 Cedric Bail
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library;
16  * if not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #ifdef HAVE_CONFIG_H
20 # include "config.h"
21 #endif
22
23 #include <string.h>
24
25 #include "eina_private.h"
26 #include "eina_inlist.h"
27 #include "eina_rbtree.h"
28 #include "eina_mempool.h"
29 #include "eina_trash.h"
30 #include "eina_log.h"
31 #include "eina_stringshare.h"
32 #include "eina_lock.h"
33
34 #include "eina_object.h"
35
36 /*============================================================================*
37  *                                  Local                                     *
38  *============================================================================*/
39
40 /**
41  * @cond LOCAL
42  */
43
44 /* If we are on a 64bits computer user bigger generation and ID */
45 /* FIXME: make it GCC independent */
46 /* FIXME: maybe having 2^32 objects doesn't make sense and 2^24 are enough
47    so instead of increasing the object count, we could just add a magic
48    to first check if the pointer is valid at all (and maybe use a pointer
49    that will always trigger a segv if we try to use it directly).
50 */
51 #ifdef _LP64
52 typedef unsigned long Eina_Object_ID;
53 typedef unsigned short Eina_Object_Generation;
54 # define EINA_GEN_OFFSET 48
55 # define EINA_ID_STR "%lu"
56 #elif _WIN64
57 typedef unsigned __int64 Eina_Object_ID;
58 typedef unsigned short Eina_Object_Generation;
59 # define EINA_GEN_OFFSET 48
60 # define EINA_ID_STR "%I64u"
61 #else
62 typedef unsigned int Eina_Object_ID;
63 typedef unsigned char Eina_Object_Generation;
64 # define EINA_GEN_OFFSET 24
65 # define EINA_ID_STR "%u"
66 #endif
67
68 typedef struct _Eina_Class_Range Eina_Class_Range;
69 typedef struct _Eina_Object_Item Eina_Object_Item;
70 typedef struct _Eina_Range Eina_Range;
71 typedef struct _Eina_Class_Top Eina_Class_Top;
72
73 struct _Eina_Range
74 {
75   EINA_INLIST;
76
77   unsigned int start;
78   unsigned int end;
79 };
80
81 struct _Eina_Object_Item
82 {
83   EINA_INLIST;
84   Eina_Class_Range *range;
85
86   Eina_Object_Item *parent;
87   Eina_Inlist *link;
88
89   unsigned int index;
90 };
91
92 struct _Eina_Class_Range
93 {
94   EINA_INLIST;
95   EINA_RBTREE;
96
97   unsigned int start;
98   unsigned int end;
99   unsigned int current;
100   unsigned int empty_count;
101
102   Eina_Class *type;
103   Eina_Trash *empty;
104
105   Eina_Object_Item **pointer_array;
106   Eina_Object_Generation generation_array[1];
107 };
108
109 struct _Eina_Class_Top
110 {
111   Eina_Class *top_parent;
112   Eina_Rbtree *range;
113   Eina_Inlist *available;
114
115   unsigned int upper_limit;
116 };
117
118 struct _Eina_Class
119 {
120   EINA_INLIST;
121
122   const char *name;
123
124   Eina_Class_Top *top;
125
126   Eina_Class *parent;
127   Eina_Inlist *childs;
128
129   Eina_Class_Callback constructor;
130   Eina_Class_Callback destructor;
131   void *data;
132
133   Eina_Inlist *allocated_range;
134
135   Eina_Mempool *mempool;
136   unsigned int class_size;
137   unsigned int object_size;
138   unsigned int pool_size;
139
140   Eina_Bool repack_needed : 1;
141
142 #ifdef EINA_HAVE_DEBUG_THREADS
143   pthread_t self;
144 #endif
145   Eina_Lock mutex;
146
147   EINA_MAGIC;
148 };
149
150 static const char EINA_MAGIC_CLASS_STR[] = "Eina Class";
151
152 static Eina_Mempool *_eina_class_mp = NULL;
153 static Eina_Mempool *_eina_top_mp = NULL;
154 static Eina_Mempool *_eina_range_mp = NULL;
155 static int _eina_object_log_dom = -1;
156 static unsigned int _eina_object_item_size = 0;
157
158 #ifdef ERR
159 #undef ERR
160 #endif
161 #define ERR(...) EINA_LOG_DOM_ERR(_eina_object_log_dom, __VA_ARGS__)
162
163 #ifdef DBG
164 #undef DBG
165 #endif
166 #define DBG(...) EINA_LOG_DOM_DBG(_eina_object_log_dom, __VA_ARGS__)
167
168 #define EINA_MAGIC_CHECK_CLASS(d, ...)                           \
169   do {                                                           \
170     if (!EINA_MAGIC_CHECK(d, EINA_MAGIC_CLASS))                  \
171       {                                                          \
172         EINA_MAGIC_FAIL(d, EINA_MAGIC_CLASS);                    \
173         return __VA_ARGS__;                                      \
174       }                                                          \
175   } while(0)
176
177 static int
178 _eina_rbtree_cmp_range(const Eina_Rbtree *node, const void *key,
179                        __UNUSED__ int length, __UNUSED__ void *data)
180 {
181   Eina_Class_Range *range;
182   Eina_Object_ID id;
183
184   range = EINA_RBTREE_CONTAINER_GET(node, Eina_Class_Range);
185   id = (Eina_Object_ID) key;
186
187   if (id < range->start) return -1;
188   else if (id >= range->end) return 1;
189   return 0;
190 }
191
192 static Eina_Rbtree_Direction
193 _eina_class_direction_range(const Eina_Rbtree *left,
194                             const Eina_Rbtree *right,
195                             __UNUSED__ void *data)
196 {
197   Eina_Class_Range *rl;
198   Eina_Class_Range *rr;
199
200   rl = EINA_RBTREE_CONTAINER_GET(left, Eina_Class_Range);
201   rr = EINA_RBTREE_CONTAINER_GET(right, Eina_Class_Range);
202
203   if (rl->start < rr->start) return EINA_RBTREE_LEFT;
204   return EINA_RBTREE_RIGHT;
205 }
206
207 /* really destroying a range and handling that case is a complex
208    problem to solve. Not handling it right now, exposing myself to
209    DoS. */
210 static void
211 _eina_range_cleanup(Eina_Class_Range *range)
212 {
213   range->current = 0;
214   range->empty = NULL;
215 }
216
217 static void
218 _eina_object_constructor_call(Eina_Class *class, void *object)
219 {
220   if (class->parent) _eina_object_constructor_call(class->parent, object);
221
222   if (class->constructor) class->constructor(class, object, class->data);
223 }
224
225 static void
226 _eina_object_destructor_call(Eina_Class *class, void *object)
227 {
228   if (class->destructor) class->destructor(class, object, class->data);
229
230   if (class->parent) _eina_object_destructor_call(class->parent, object);
231 }
232
233 static Eina_Object*
234 _eina_object_get(Eina_Object_Item *item)
235 {
236   Eina_Object_Generation gen;
237   Eina_Object_ID id;
238
239   if (!item) return NULL;
240
241   gen = item->range->generation_array[item->index];
242
243   id = ((Eina_Object_ID) gen << EINA_GEN_OFFSET) + item->range->start + item->index;
244
245   return (Eina_Object *) id;
246 }
247
248 static Eina_Object_Item *
249 _eina_object_find_item(Eina_Class *class, Eina_Object *object)
250 {
251   Eina_Class_Range *matched;
252   Eina_Object_Item *item;
253   Eina_Class *search;
254   Eina_Rbtree *match;
255   Eina_Object_Generation generation;
256   Eina_Object_ID id;
257   Eina_Object_ID idx;
258
259   id = (Eina_Object_ID) object;
260   idx = id & (((Eina_Object_ID) 1 << EINA_GEN_OFFSET) - 1);
261   generation = id & !(((Eina_Object_ID) 1 << EINA_GEN_OFFSET) - 1);
262
263   /* Try to find the ID */
264   match = eina_rbtree_inline_lookup(class->top->range,
265                                     (void*) idx, sizeof (Eina_Object_ID),
266                                     _eina_rbtree_cmp_range, NULL);
267   /* ID not found, invalid pointer ! */
268   if (!match)
269     {
270       ERR("%p: ID ["EINA_ID_STR"] not found in class hiearchy of [%s].",
271           object, idx, class->name);
272       return NULL;
273     }
274   matched = EINA_RBTREE_CONTAINER_GET(match, Eina_Class_Range);
275
276   /* generation mismatch, invalid pointer ! */
277   if (generation != matched->generation_array[idx - matched->start])
278     {
279       ERR("%p: generation mismatch [%i] vs [%i].",
280           object, generation, matched->generation_array[idx - matched->start]);
281       return NULL;
282     }
283
284   /* does it belong to the right class ? */
285   for (search = matched->type; search && search != class; search = search->parent)
286     ;
287
288   /* class match request or invalid pointer ! */
289   if (search != class)
290     {
291       ERR("%p: from class [%s] is not in the hierarchie of [%s].",
292           object, matched->type->name, class->name);
293       return NULL;
294     }
295
296   /* retrieve pointer */
297   item = matched->pointer_array[id - matched->start];
298   /* allocated or invalid pointer ? */
299   if (!item)
300     {
301       ERR("%p: ID is not allocated.", object);
302       return NULL;
303     }
304
305   /* be aware, that because we use eina_trash to store empty pointer after first use,
306      pointer could be != NULL and still be empty. Need another pool of data somewhere
307      to store the state of the allocation... Is it needed ?
308    */
309
310   return item;
311 }
312
313 static void
314 _eina_object_item_del(Eina_Object_Item *item)
315 {
316   Eina_Class *class;
317
318   class = item->range->type;
319   _eina_object_destructor_call(class,
320                                (unsigned char*) item + _eina_object_item_size);
321
322   eina_trash_push(&item->range->empty, item->range->pointer_array + item->index);
323   item->range->generation_array[item->index]++;
324   item->range->empty_count++;
325
326   if (item->range->empty_count == item->range->end - item->range->start)
327     _eina_range_cleanup(item->range);
328   item->range = NULL;
329
330   if (item->parent)
331     item->parent->link = eina_inlist_remove(item->parent->link, EINA_INLIST_GET(item));
332   item->parent = NULL;
333
334   while (item->link)
335     {
336       Eina_Object_Item *child;
337
338       child = EINA_INLIST_CONTAINER_GET(item->link, Eina_Object_Item);
339       _eina_object_item_del(child);
340     }
341
342   eina_mempool_free(class->mempool, item);
343 }
344
345 static Eina_Class_Range *
346 _eina_class_empty_range_get(Eina_Inlist *list)
347 {
348   while (list)
349     {
350       Eina_Class_Range *range;
351
352       range = EINA_INLIST_CONTAINER_GET(list, Eina_Class_Range);
353       if (range->empty_count > 0)
354         return range;
355
356       list = list->next;
357     }
358
359   return NULL;
360 }
361
362 static Eina_Class_Range *
363 _eina_class_range_add(Eina_Class *class)
364 {
365   Eina_Class_Range *range;
366   unsigned char *tmp;
367   Eina_Range *av = NULL;
368
369   range = malloc(sizeof (Eina_Class_Range)
370                  + sizeof (Eina_Object_Item*) * class->pool_size
371                  + sizeof (Eina_Object_Generation) * (class->pool_size - 1));
372   if (!range) return NULL;
373
374   tmp = (void*) (range + 1);
375   tmp += sizeof (Eina_Object_Generation) * (class->pool_size - 1);
376
377   range->pointer_array = (Eina_Object_Item**) tmp;
378
379   /* no need to fix generation to a specific value as random value should be just fine */
380   memset(range->pointer_array, 0, sizeof (Eina_Object_Item*) * class->pool_size);
381
382   range->current = 0;
383   range->type = class;
384   range->empty = NULL;
385
386   /* and now find an empty block */
387   EINA_INLIST_FOREACH(class->top->available, av)
388     if ((av->end - av->start) == class->pool_size)
389       break;
390
391   if (av)
392     {
393       range->start = av->start;
394       range->end = av->end;
395
396       class->top->available = eina_inlist_remove(class->top->available,
397                                                  EINA_INLIST_GET(av));
398       eina_mempool_free(_eina_range_mp, av);
399     }
400   else
401     {
402       range->start = class->top->upper_limit;
403       range->end = range->start + class->pool_size;
404       class->top->upper_limit = range->end;
405     }
406
407   return range;
408 }
409
410 static void
411 _eina_class_range_del(Eina_Class_Range *range)
412 {
413   Eina_Class_Top *top;
414   Eina_Range *keep;
415
416   top = range->type->top;
417
418   keep = eina_mempool_malloc(_eina_range_mp, sizeof (Eina_Range));
419   if (!keep)
420     {
421       ERR("Not enougth memory to keep track of allocated range.");
422       goto delete_class_range;
423     }
424
425   keep->start = range->start;
426   keep->end = range->end;
427
428   top->available = eina_inlist_prepend(top->available,
429                                        EINA_INLIST_GET(keep));
430
431  delete_class_range:
432   top->range = eina_rbtree_inline_remove(top->range, EINA_RBTREE_GET(range),
433                                          _eina_class_direction_range, NULL);
434   range->type->allocated_range = eina_inlist_remove(range->type->allocated_range,
435                                                     EINA_INLIST_GET(range));
436   free(range);
437 }
438
439 static void
440 _eina_class_range_repack(void *dst, void *src, void *data)
441 {
442   Eina_Object_Item *di = dst;
443   Eina_Object_Item *si = src;
444   Eina_Class *class = data;
445
446   (void) class;
447
448   si->range->pointer_array[si->index] = di;
449
450   /* FIXME: We could just lock the right Eina_Class_Range 
451      here instead of locking all the Class */
452 }
453
454 /**
455  * @endcond
456  */
457
458 Eina_Bool
459 eina_object_init(void)
460 {
461   _eina_object_log_dom = eina_log_domain_register("eina_object",
462                                                   EINA_LOG_COLOR_DEFAULT);
463   if (_eina_object_log_dom < 0)
464     {
465       EINA_LOG_ERR("Could not register log domain: eina_list");
466       return EINA_FALSE;
467     }
468
469   _eina_class_mp = eina_mempool_add("chained_mempool", "class", 
470                                     NULL, sizeof (Eina_Class), 16);
471   if (!_eina_class_mp)
472     {
473       ERR("ERROR: Mempool for Eina_Class cannot be allocated in object init.");
474       goto on_init_fail;
475     }
476
477   _eina_top_mp = eina_mempool_add("chained_mempool", "top",
478                                   NULL, sizeof (Eina_Class_Top), 16);
479   if (!_eina_top_mp)
480     {
481       ERR("ERROR: Mempool for Eina_Class_Top cannot be allocated in object init.");
482       goto on_init_fail;
483     }
484
485   _eina_range_mp = eina_mempool_add("chained_mempool", "range",
486                                     NULL, sizeof (Eina_Range), 16);
487   if (!_eina_range_mp)
488     {
489       ERR("ERROR: Mempool for Eina_Class_Top cannot be allocated in object init.");
490       goto on_init_fail;
491     }
492
493 #define EMS(n) eina_magic_string_static_set(n, n ## _STR)
494   EMS(EINA_MAGIC_CLASS);
495 #undef EMS
496
497   _eina_object_item_size = eina_mempool_alignof(sizeof (Eina_Object_Item));
498
499   return EINA_TRUE;
500
501  on_init_fail:
502   eina_log_domain_unregister(_eina_object_log_dom);
503   _eina_object_log_dom = -1;
504
505   if (_eina_top_mp)
506     {
507       eina_mempool_del(_eina_top_mp);
508       _eina_top_mp = NULL;
509     }
510
511   if (_eina_class_mp)
512     {
513       eina_mempool_del(_eina_class_mp);
514       _eina_class_mp = NULL;
515     }
516
517   return EINA_FALSE;
518 }
519
520 Eina_Bool
521 eina_object_shutdown(void)
522 {
523   eina_mempool_del(_eina_class_mp);
524   eina_mempool_del(_eina_top_mp);
525
526   eina_log_domain_unregister(_eina_object_log_dom);
527   _eina_object_log_dom = -1;
528   return EINA_TRUE;
529 }
530
531 Eina_Class *
532 eina_class_new(const char *name,
533                unsigned int class_size,
534                unsigned int pool_size,
535                Eina_Class_Callback constructor,
536                Eina_Class_Callback destructor,
537                Eina_Class *parent,
538                void *data)
539 {
540   Eina_Class *c;
541   unsigned int object_size = class_size;
542
543   if (parent) EINA_MAGIC_CHECK_CLASS(parent, NULL);
544
545   c = eina_mempool_malloc(_eina_class_mp, sizeof (Eina_Class));
546   if (!c) return NULL;
547
548   c->parent = parent;
549   if (parent)
550     {
551       parent->childs = eina_inlist_append(parent->childs,
552                                           EINA_INLIST_GET(c));
553       c->top = parent->top;
554     }
555   else
556     {
557       c->top = eina_mempool_malloc(_eina_top_mp, sizeof (Eina_Class_Top));
558
559       c->top->top_parent = c;
560       c->top->range = NULL;
561       c->top->available = NULL;
562       c->top->upper_limit = 0;
563     }
564
565   /* Build complete object size and find top parent */
566   if (parent) object_size += parent->object_size;
567
568   c->name = eina_stringshare_add(name);
569   c->class_size = class_size;
570   c->pool_size = pool_size;
571   c->object_size = object_size;
572   c->mempool = eina_mempool_add("chained_mempool", "range",
573                                 NULL, 
574                                 _eina_object_item_size + object_size, pool_size); 
575
576   c->constructor = constructor;
577   c->destructor = destructor;
578   c->data = data;
579
580   c->allocated_range = NULL;
581   c->childs = NULL;
582
583 #ifdef EINA_HAVE_DEBUG_THREADS
584   c->self = pthread_self();
585 #endif
586   eina_lock_new(&c->mutex);
587
588   EINA_MAGIC_SET(c, EINA_MAGIC_CLASS);
589
590   return c;
591 }
592
593 const char *
594 eina_class_name_get(Eina_Class *class)
595 {
596   EINA_MAGIC_CHECK_CLASS(class, NULL);
597
598   return class->name;  
599 }
600
601 unsigned int
602 eina_class_size_get(Eina_Class *class)
603 {
604   EINA_MAGIC_CHECK_CLASS(class, 0);
605
606   return class->class_size;
607 }
608
609 unsigned int
610 eina_class_object_size_get(Eina_Class *class)
611 {
612   EINA_MAGIC_CHECK_CLASS(class, 0);
613
614   return class->object_size;
615 }
616
617 void
618 eina_class_del(Eina_Class *class)
619 {
620   EINA_MAGIC_CHECK_CLASS(class);
621
622   EINA_MAGIC_SET(class, 0);
623
624   while (class->allocated_range)
625     _eina_class_range_del(EINA_INLIST_CONTAINER_GET(class->allocated_range,
626                                                     Eina_Class_Range));
627
628   while (class->childs)
629     {
630       Eina_Class *child;
631
632       child = EINA_INLIST_CONTAINER_GET(class->childs, Eina_Class);
633       eina_class_del(child);
634     }
635
636   if (class->parent)
637     {
638       class->parent->childs = eina_inlist_remove(class->parent->childs,
639                                                  EINA_INLIST_GET(class));
640     }
641   else
642     {
643       while (class->top->available)
644         {
645           Eina_Range *range;
646
647           range = EINA_INLIST_CONTAINER_GET(class->top->available, Eina_Range);
648           class->top->available = eina_inlist_remove(class->top->available,
649                                                      class->top->available);
650           eina_mempool_free(_eina_range_mp, range);
651         }
652     }
653
654 #ifdef EINA_HAVE_DEBUG_THREADS
655   assert(pthread_equal(class->self, pthread_self()));
656 #endif
657   eina_lock_free(&class->mutex);
658
659   eina_mempool_del(class->mempool);
660   eina_mempool_free(_eina_class_mp, class);
661 }
662
663 void
664 eina_class_repack(Eina_Class *class)
665 {
666   Eina_Class *child;
667
668   EINA_MAGIC_CHECK_CLASS(class);
669
670   if (!eina_lock_take(&class->mutex))
671     {
672 #ifdef EINA_HAVE_DEBUG_THREADS
673       assert(pthread_equal(class->self, pthread_self()));
674 #endif
675     }
676
677   eina_mempool_repack(class->mempool, _eina_class_range_repack, class);
678
679   eina_lock_release(&class->mutex);
680
681   EINA_INLIST_FOREACH(class->childs, child)
682     eina_class_repack(child);
683 }
684
685 Eina_Object *
686 eina_object_add(Eina_Class *class)
687 {
688   Eina_Class_Range *range;
689   Eina_Object_Item **object;
690   int localid;
691
692   EINA_MAGIC_CHECK_CLASS(class, NULL);
693
694   /* No need to lock the class as we don't access/modify the pointer inside
695    * this function. */
696
697   range = _eina_class_empty_range_get(class->allocated_range);
698   if (!range) range = _eina_class_range_add(class);
699
700   if (range->empty_count == 0)
701     {
702       ERR("The impossible happen, range is empty when it should not !");
703       return NULL;
704     }
705
706   range->empty_count--;
707
708   object = eina_trash_pop(&range->empty);
709   if (!object) object = range->pointer_array + range->current++;
710
711   localid = object - range->pointer_array;
712
713   *object = eina_mempool_malloc(class->mempool, 
714                                 class->object_size + _eina_object_item_size);
715
716   (*object)->index = localid;
717   (*object)->link = NULL;
718   (*object)->range = range;
719
720   _eina_object_constructor_call(class,
721                                 ((unsigned char*)(*object)) + _eina_object_item_size);
722
723   if (!(++range->generation_array[localid]))
724     ++range->generation_array[localid];
725
726   return _eina_object_get(*object);
727 }
728
729 void *
730 eina_object_pointer_get(Eina_Class *class,
731                         Eina_Object *object)
732 {
733   Eina_Object_Item *item;
734   unsigned char *mem = NULL;
735
736   if (!object) return NULL;
737   EINA_MAGIC_CHECK_CLASS(class, NULL);
738
739   if (!eina_lock_take(&class->mutex))
740     {
741 #ifdef EINA_HAVE_DEBUG_THREADS
742       assert(pthread_equal(class->self, pthread_self()));
743 #endif
744     }
745
746   item = _eina_object_find_item(class, object);
747   if (!item) goto on_error;
748
749   mem = (unsigned char*) item + _eina_object_item_size;
750
751  on_error:
752   eina_lock_release(&class->mutex);
753
754   return mem;
755 }
756
757 void
758 eina_object_del(Eina_Class *class,
759                 Eina_Object *object)
760 {
761   Eina_Object_Item *item;
762
763   if (!object) return ;
764   EINA_MAGIC_CHECK_CLASS(class);
765
766   if (!eina_lock_take(&class->mutex))
767     {
768 #ifdef EINA_HAVE_DEBUG_THREADS
769       assert(pthread_equal(class->self, pthread_self()));
770 #endif
771     }
772
773   item = _eina_object_find_item(class, object);
774   if (!item) goto on_error;
775
776   _eina_object_item_del(item);
777
778  on_error:
779   eina_lock_release(&class->mutex);
780 }
781
782 Eina_Bool
783 eina_object_parent_set(Eina_Class *parent_class, Eina_Object *parent,
784                        Eina_Class *object_class, Eina_Object *object)
785 {
786   Eina_Object_Item *parent_item;
787   Eina_Object_Item *object_item;
788
789   if (!parent) return EINA_FALSE;
790   if (!object) return EINA_FALSE;
791   EINA_MAGIC_CHECK_CLASS(parent_class, EINA_FALSE);
792   EINA_MAGIC_CHECK_CLASS(object_class, EINA_FALSE);
793
794   if (!eina_lock_take(&parent_class->mutex))
795     {
796 #ifdef EINA_HAVE_DEBUG_THREADS
797       assert(pthread_equal(parent_class->self, pthread_self()));
798 #endif
799     }
800
801   if (!eina_lock_take(&object_class->mutex))
802     {
803 #ifdef EINA_HAVE_DEBUG_THREADS
804       assert(pthread_equal(object_class->self, pthread_self()));
805 #endif
806     }
807
808   parent_item = _eina_object_find_item(parent_class, parent);
809   if (!parent_item) return EINA_FALSE;
810
811   object_item = _eina_object_find_item(object_class, object);
812   if (!object_item) return EINA_FALSE;
813
814   if (object_item->parent)
815     object_item->parent->link = eina_inlist_remove(object_item->parent->link,
816                                                    EINA_INLIST_GET(object_item));
817
818   object_item->parent = parent_item;
819   parent_item->link = eina_inlist_append(parent_item->link,
820                                          EINA_INLIST_GET(object_item));
821
822   eina_lock_release(&parent_class->mutex);
823   eina_lock_release(&object_class->mutex);
824
825   return EINA_TRUE;
826 }
827
828 Eina_Object *
829 eina_object_parent_get(Eina_Class *class, Eina_Object *object)
830 {
831   Eina_Object_Item *object_item;
832   Eina_Object *or = NULL;
833
834   if (!object) return EINA_FALSE;
835   EINA_MAGIC_CHECK_CLASS(class, EINA_FALSE);
836
837   if (!eina_lock_take(&class->mutex))
838     {
839 #ifdef EINA_HAVE_DEBUG_THREADS
840       assert(pthread_equal(class->self, pthread_self()));
841 #endif
842     }
843
844   object_item = _eina_object_find_item(class, object);
845   if (object_item)
846     or = _eina_object_get(object_item->parent);
847
848   eina_lock_release(&class->mutex);
849
850   return or;
851 }
852