eina: improve on/off and debugging lock.
[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 independant */
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_THREADS
143 # ifdef EINA_HAVE_DEBUG_THREADS
144   pthread_t self;
145 # endif
146   Eina_Lock mutex;
147 #endif
148
149   EINA_MAGIC;
150 };
151
152 static const char EINA_MAGIC_CLASS_STR[] = "Eina Class";
153
154 static Eina_Mempool *_eina_class_mp = NULL;
155 static Eina_Mempool *_eina_top_mp = NULL;
156 static Eina_Mempool *_eina_range_mp = NULL;
157 static int _eina_object_log_dom = -1;
158 static unsigned int _eina_object_item_size = 0;
159
160 #ifdef ERR
161 #undef ERR
162 #endif
163 #define ERR(...) EINA_LOG_DOM_ERR(_eina_object_log_dom, __VA_ARGS__)
164
165 #ifdef DBG
166 #undef DBG
167 #endif
168 #define DBG(...) EINA_LOG_DOM_DBG(_eina_object_log_dom, __VA_ARGS__)
169
170 #define EINA_MAGIC_CHECK_CLASS(d, ...)                           \
171   do {                                                           \
172     if (!EINA_MAGIC_CHECK(d, EINA_MAGIC_CLASS))                  \
173       {                                                          \
174         EINA_MAGIC_FAIL(d, EINA_MAGIC_CLASS);                    \
175         return __VA_ARGS__;                                      \
176       }                                                          \
177   } while(0)
178
179 static int
180 _eina_rbtree_cmp_range(const Eina_Rbtree *node, const void *key,
181                        __UNUSED__ int length, __UNUSED__ void *data)
182 {
183   Eina_Class_Range *range;
184   Eina_Object_ID id;
185
186   range = EINA_RBTREE_CONTAINER_GET(node, Eina_Class_Range);
187   id = (Eina_Object_ID) key;
188
189   if (id < range->start) return -1;
190   else if (id >= range->end) return 1;
191   return 0;
192 }
193
194 static Eina_Rbtree_Direction
195 _eina_class_direction_range(const Eina_Rbtree *left,
196                             const Eina_Rbtree *right,
197                             __UNUSED__ void *data)
198 {
199   Eina_Class_Range *rl;
200   Eina_Class_Range *rr;
201
202   rl = EINA_RBTREE_CONTAINER_GET(left, Eina_Class_Range);
203   rr = EINA_RBTREE_CONTAINER_GET(right, Eina_Class_Range);
204
205   if (rl->start < rr->start) return EINA_RBTREE_LEFT;
206   return EINA_RBTREE_RIGHT;
207 }
208
209 /* really destroying a range and handling that case is a complex
210    problem to solve. Not handling it right now, exposing myself to
211    DoS. */
212 static void
213 _eina_range_cleanup(Eina_Class_Range *range)
214 {
215   range->current = 0;
216   range->empty = NULL;
217 }
218
219 static void
220 _eina_object_constructor_call(Eina_Class *class, void *object)
221 {
222   if (class->parent) _eina_object_constructor_call(class->parent, object);
223
224   if (class->constructor) class->constructor(class, object, class->data);
225 }
226
227 static void
228 _eina_object_destructor_call(Eina_Class *class, void *object)
229 {
230   if (class->destructor) class->destructor(class, object, class->data);
231
232   if (class->parent) _eina_object_destructor_call(class->parent, object);
233 }
234
235 static Eina_Object*
236 _eina_object_get(Eina_Object_Item *item)
237 {
238   Eina_Object_Generation gen;
239   Eina_Object_ID id;
240
241   if (!item) return NULL;
242
243   gen = item->range->generation_array[item->index];
244
245   id = ((Eina_Object_ID) gen << EINA_GEN_OFFSET) + item->range->start + item->index;
246
247   return (Eina_Object *) id;
248 }
249
250 static Eina_Object_Item *
251 _eina_object_find_item(Eina_Class *class, Eina_Object *object)
252 {
253   Eina_Class_Range *matched;
254   Eina_Object_Item *item;
255   Eina_Class *search;
256   Eina_Rbtree *match;
257   Eina_Object_Generation generation;
258   Eina_Object_ID id;
259   Eina_Object_ID idx;
260
261   id = (Eina_Object_ID) object;
262   idx = id & (((Eina_Object_ID) 1 << EINA_GEN_OFFSET) - 1);
263   generation = id & !(((Eina_Object_ID) 1 << EINA_GEN_OFFSET) - 1);
264
265   /* Try to find the ID */
266   match = eina_rbtree_inline_lookup(class->top->range,
267                                     (void*) idx, sizeof (Eina_Object_ID),
268                                     _eina_rbtree_cmp_range, NULL);
269   /* ID not found, invalid pointer ! */
270   if (!match)
271     {
272       ERR("%p: ID ["EINA_ID_STR"] not found in class hiearchy of [%s].",
273           object, idx, class->name);
274       return NULL;
275     }
276   matched = EINA_RBTREE_CONTAINER_GET(match, Eina_Class_Range);
277
278   /* generation mismatch, invalid pointer ! */
279   if (generation != matched->generation_array[idx - matched->start])
280     {
281       ERR("%p: generation mismatch [%i] vs [%i].",
282           object, generation, matched->generation_array[idx - matched->start]);
283       return NULL;
284     }
285
286   /* does it belong to the right class ? */
287   for (search = matched->type; search && search != class; search = search->parent)
288     ;
289
290   /* class match request or invalid pointer ! */
291   if (search != class)
292     {
293       ERR("%p: from class [%s] is not in the hierarchie of [%s].",
294           object, matched->type->name, class->name);
295       return NULL;
296     }
297
298   /* retrieve pointer */
299   item = matched->pointer_array[id - matched->start];
300   /* allocated or invalid pointer ? */
301   if (!item)
302     {
303       ERR("%p: ID is not allocated.", object);
304       return NULL;
305     }
306
307   /* be aware, that because we use eina_trash to store empty pointer after first use,
308      pointer could be != NULL and still be empty. Need another pool of data somewhere
309      to store the state of the allocation... Is it needed ?
310    */
311
312   return item;
313 }
314
315 static void
316 _eina_object_item_del(Eina_Object_Item *item)
317 {
318   Eina_Class *class;
319
320   class = item->range->type;
321   _eina_object_destructor_call(class,
322                                (unsigned char*) item + _eina_object_item_size);
323
324   eina_trash_push(&item->range->empty, item->range->pointer_array + item->index);
325   item->range->generation_array[item->index]++;
326   item->range->empty_count++;
327
328   if (item->range->empty_count == item->range->end - item->range->start)
329     _eina_range_cleanup(item->range);
330   item->range = NULL;
331
332   if (item->parent)
333     item->parent->link = eina_inlist_remove(item->parent->link, EINA_INLIST_GET(item));
334   item->parent = NULL;
335
336   while (item->link)
337     {
338       Eina_Object_Item *child;
339
340       child = EINA_INLIST_CONTAINER_GET(item->link, Eina_Object_Item);
341       _eina_object_item_del(child);
342     }
343
344   eina_mempool_free(class->mempool, item);
345 }
346
347 static Eina_Class_Range *
348 _eina_class_empty_range_get(Eina_Inlist *list)
349 {
350   while (list)
351     {
352       Eina_Class_Range *range;
353
354       range = EINA_INLIST_CONTAINER_GET(list, Eina_Class_Range);
355       if (range->empty_count > 0)
356         return range;
357
358       list = list->next;
359     }
360
361   return NULL;
362 }
363
364 static Eina_Class_Range *
365 _eina_class_range_add(Eina_Class *class)
366 {
367   Eina_Class_Range *range;
368   unsigned char *tmp;
369   Eina_Range *av = NULL;
370
371   range = malloc(sizeof (Eina_Class_Range)
372                  + sizeof (Eina_Object_Item*) * class->pool_size
373                  + sizeof (Eina_Object_Generation) * (class->pool_size - 1));
374   if (!range) return NULL;
375
376   tmp = (void*) (range + 1);
377   tmp += sizeof (Eina_Object_Generation) * (class->pool_size - 1);
378
379   range->pointer_array = (Eina_Object_Item**) tmp;
380
381   /* no need to fix generation to a specific value as random value should be just fine */
382   memset(range->pointer_array, 0, sizeof (Eina_Object_Item*) * class->pool_size);
383
384   range->current = 0;
385   range->type = class;
386   range->empty = NULL;
387
388   /* and now find an empty block */
389   EINA_INLIST_FOREACH(class->top->available, av)
390     if (av->end - av->start == class->pool_size)
391       break;
392
393   if (av)
394     {
395       range->start = av->start;
396       range->end = av->end;
397
398       class->top->available = eina_inlist_remove(class->top->available,
399                                                  EINA_INLIST_GET(av));
400       eina_mempool_free(_eina_range_mp, av);
401     }
402   else
403     {
404       range->start = class->top->upper_limit;
405       range->end = range->start + class->pool_size;
406       class->top->upper_limit = range->end;
407     }
408
409   return range;
410 }
411
412 static void
413 _eina_class_range_del(Eina_Class_Range *range)
414 {
415   Eina_Class_Top *top;
416   Eina_Range *keep;
417
418   top = range->type->top;
419
420   keep = eina_mempool_malloc(_eina_range_mp, sizeof (Eina_Range));
421   if (!keep)
422     {
423       ERR("Not enougth memory to keep track of allocated range.");
424       goto delete_class_range;
425     }
426
427   keep->start = range->start;
428   keep->end = range->end;
429
430   top->available = eina_inlist_prepend(top->available,
431                                        EINA_INLIST_GET(keep));
432
433  delete_class_range:
434   top->range = eina_rbtree_inline_remove(top->range, EINA_RBTREE_GET(range),
435                                          _eina_class_direction_range, NULL);
436   range->type->allocated_range = eina_inlist_remove(range->type->allocated_range,
437                                                     EINA_INLIST_GET(range));
438   free(range);
439 }
440
441 static void
442 _eina_class_range_repack(void *dst, void *src, void *data)
443 {
444   Eina_Object_Item *di = dst;
445   Eina_Object_Item *si = src;
446   Eina_Class *class = data;
447
448   (void) class;
449
450   si->range->pointer_array[si->index] = di;
451
452   /* FIXME: We could just lock the right Eina_Class_Range 
453      here instead of locking all the Class */
454 }
455
456 /**
457  * @}
458  */
459
460 Eina_Bool
461 eina_object_init(void)
462 {
463   _eina_object_log_dom = eina_log_domain_register("eina_object",
464                                                   EINA_LOG_COLOR_DEFAULT);
465   if (_eina_object_log_dom < 0)
466     {
467       EINA_LOG_ERR("Could not register log domain: eina_list");
468       return EINA_FALSE;
469     }
470
471   _eina_class_mp = eina_mempool_add("chained_mempool", "class", 
472                                     NULL, sizeof (Eina_Class), 64);
473   if (!_eina_class_mp)
474     {
475       ERR("ERROR: Mempool for Eina_Class cannot be allocated in object init.");
476       goto on_init_fail;
477     }
478
479   _eina_top_mp = eina_mempool_add("chained_mempool", "top",
480                                   NULL, sizeof (Eina_Class_Top), 64);
481   if (!_eina_top_mp)
482     {
483       ERR("ERROR: Mempool for Eina_Class_Top cannot be allocated in object init.");
484       goto on_init_fail;
485     }
486
487   _eina_range_mp = eina_mempool_add("chained_mempool", "range",
488                                     NULL, sizeof (Eina_Range), 64);
489   if (!_eina_range_mp)
490     {
491       ERR("ERROR: Mempool for Eina_Class_Top cannot be allocated in object init.");
492       goto on_init_fail;
493     }
494
495 #define EMS(n) eina_magic_string_static_set(n, n ## _STR)
496   EMS(EINA_MAGIC_CLASS);
497 #undef EMS
498
499   _eina_object_item_size = eina_mempool_alignof(sizeof (Eina_Object_Item));
500
501   return EINA_TRUE;
502
503  on_init_fail:
504   eina_log_domain_unregister(_eina_object_log_dom);
505   _eina_object_log_dom = -1;
506
507   if (_eina_top_mp)
508     {
509       eina_mempool_del(_eina_top_mp);
510       _eina_top_mp = NULL;
511     }
512
513   if (_eina_class_mp)
514     {
515       eina_mempool_del(_eina_class_mp);
516       _eina_class_mp = NULL;
517     }
518
519   return EINA_FALSE;
520 }
521
522 Eina_Bool
523 eina_object_shutdown(void)
524 {
525   eina_mempool_del(_eina_class_mp);
526   eina_mempool_del(_eina_top_mp);
527
528   eina_log_domain_unregister(_eina_object_log_dom);
529   _eina_object_log_dom = -1;
530   return EINA_TRUE;
531 }
532
533 Eina_Class *
534 eina_class_new(const char *name,
535                unsigned int class_size,
536                unsigned int pool_size,
537                Eina_Class_Callback constructor,
538                Eina_Class_Callback destructor,
539                Eina_Class *parent,
540                void *data)
541 {
542   Eina_Class *c;
543   unsigned int object_size = class_size;
544
545   if (parent) EINA_MAGIC_CHECK_CLASS(parent, NULL);
546
547   c = eina_mempool_malloc(_eina_class_mp, sizeof (Eina_Class));
548   if (!c) return NULL;
549
550   c->parent = parent;
551   if (parent)
552     {
553       parent->childs = eina_inlist_append(parent->childs,
554                                           EINA_INLIST_GET(c));
555       c->top = parent->top;
556     }
557   else
558     {
559       c->top = eina_mempool_malloc(_eina_top_mp, sizeof (Eina_Class_Top));
560
561       c->top->top_parent = c;
562       c->top->range = NULL;
563       c->top->available = NULL;
564       c->top->upper_limit = 0;
565     }
566
567   /* Build complete object size and find top parent */
568   if (parent) object_size += parent->object_size;
569
570   c->name = eina_stringshare_add(name);
571   c->class_size = class_size;
572   c->pool_size = pool_size;
573   c->object_size = object_size;
574   c->mempool = eina_mempool_add("chained_mempool", "range",
575                                 NULL, 
576                                 _eina_object_item_size + object_size, pool_size); 
577
578   c->constructor = constructor;
579   c->destructor = destructor;
580   c->data = data;
581
582   c->allocated_range = NULL;
583   c->childs = NULL;
584
585 #ifdef EINA_HAVE_THREADS
586 # ifdef EINA_HAVE_DEBUG_THREADS
587   c->self = pthread_self();
588 # endif
589   eina_lock_new(&c->mutex);
590 #endif
591
592   EINA_MAGIC_SET(c, EINA_MAGIC_CLASS);
593
594   return c;
595 }
596
597 const char *
598 eina_class_name_get(Eina_Class *class)
599 {
600   EINA_MAGIC_CHECK_CLASS(class, NULL);
601
602   return class->name;  
603 }
604
605 unsigned int
606 eina_class_size_get(Eina_Class *class)
607 {
608   EINA_MAGIC_CHECK_CLASS(class, 0);
609
610   return class->class_size;
611 }
612
613 unsigned int
614 eina_class_object_size_get(Eina_Class *class)
615 {
616   EINA_MAGIC_CHECK_CLASS(class, 0);
617
618   return class->object_size;
619 }
620
621 void
622 eina_class_del(Eina_Class *class)
623 {
624   EINA_MAGIC_CHECK_CLASS(class);
625
626   EINA_MAGIC_SET(class, 0);
627
628   while (class->allocated_range)
629     _eina_class_range_del(EINA_INLIST_CONTAINER_GET(class->allocated_range,
630                                                     Eina_Class_Range));
631
632   while (class->childs)
633     {
634       Eina_Class *child;
635
636       child = EINA_INLIST_CONTAINER_GET(class->childs, Eina_Class);
637       eina_class_del(child);
638     }
639
640   if (class->parent)
641     {
642       class->parent->childs = eina_inlist_remove(class->parent->childs,
643                                                  EINA_INLIST_GET(class));
644     }
645   else
646     {
647       while (class->top->available)
648         {
649           Eina_Range *range;
650
651           range = EINA_INLIST_CONTAINER_GET(class->top->available, Eina_Range);
652           class->top->available = eina_inlist_remove(class->top->available,
653                                                      class->top->available);
654           eina_mempool_free(_eina_range_mp, range);
655         }
656     }
657
658 #ifdef EINA_HAVE_THREADS
659 # ifdef EINA_HAVE_DEBUG_THREADS
660   assert(pthread_equal(class->self, pthread_self()));
661 # endif
662   eina_lock_free(&class->mutex);
663 #endif
664
665   eina_mempool_del(class->mempool);
666   eina_mempool_free(_eina_class_mp, class);
667 }
668
669 void
670 eina_class_repack(Eina_Class *class)
671 {
672   Eina_Class *child;
673
674   EINA_MAGIC_CHECK_CLASS(class);
675
676   if (!eina_lock_take(&class->mutex))
677     {
678 #ifdef EINA_HAVE_DEBUG_THREADS
679       assert(pthread_equal(class->self, pthread_self()));
680 #endif
681     }
682
683   eina_mempool_repack(class->mempool, _eina_class_range_repack, class);
684
685   eina_lock_release(&class->mutex);
686
687   EINA_INLIST_FOREACH(class->childs, child)
688     eina_class_repack(child);
689 }
690
691 Eina_Object *
692 eina_object_add(Eina_Class *class)
693 {
694   Eina_Class_Range *range;
695   Eina_Object_Item **object;
696   int localid;
697
698   EINA_MAGIC_CHECK_CLASS(class, NULL);
699
700   /* No need to lock the class as we don't access/modify the pointer inside
701    * this function. */
702
703   range = _eina_class_empty_range_get(class->allocated_range);
704   if (!range) range = _eina_class_range_add(class);
705
706   if (range->empty_count == 0)
707     {
708       ERR("The impossible happen, range is empty when it should not !");
709       return NULL;
710     }
711
712   range->empty_count--;
713
714   object = eina_trash_pop(&range->empty);
715   if (!object) object = range->pointer_array + range->current++;
716
717   localid = object - range->pointer_array;
718
719   *object = eina_mempool_malloc(class->mempool, 
720                                 class->object_size + _eina_object_item_size);
721
722   (*object)->index = localid;
723   (*object)->link = NULL;
724   (*object)->range = range;
725
726   _eina_object_constructor_call(class,
727                                 ((unsigned char*)(*object)) + _eina_object_item_size);
728
729   if (!(++range->generation_array[localid]))
730     ++range->generation_array[localid];
731
732   return _eina_object_get(*object);
733 }
734
735 void *
736 eina_object_pointer_get(Eina_Class *class,
737                         Eina_Object *object)
738 {
739   Eina_Object_Item *item;
740   unsigned char *mem = NULL;
741
742   if (!object) return NULL;
743   EINA_MAGIC_CHECK_CLASS(class, NULL);
744
745   if (!eina_lock_take(&class->mutex))
746     {
747 #ifdef EINA_HAVE_DEBUG_THREADS
748       assert(pthread_equal(class->self, pthread_self()));
749 #endif
750     }
751
752   item = _eina_object_find_item(class, object);
753   if (!item) goto on_error;
754
755   mem = (unsigned char*) item + _eina_object_item_size;
756
757  on_error:
758   eina_lock_release(&class->mutex);
759
760   return mem;
761 }
762
763 void
764 eina_object_del(Eina_Class *class,
765                 Eina_Object *object)
766 {
767   Eina_Object_Item *item;
768
769   if (!object) return ;
770   EINA_MAGIC_CHECK_CLASS(class);
771
772   if (!eina_lock_take(&class->mutex))
773     {
774 #ifdef EINA_HAVE_DEBUG_THREADS
775       assert(pthread_equal(class->self, pthread_self()));
776 #endif
777     }
778
779   item = _eina_object_find_item(class, object);
780   if (!item) goto on_error;
781
782   _eina_object_item_del(item);
783
784  on_error:
785   eina_lock_release(&class->mutex);
786 }
787
788 Eina_Bool
789 eina_object_parent_set(Eina_Class *parent_class, Eina_Object *parent,
790                        Eina_Class *object_class, Eina_Object *object)
791 {
792   Eina_Object_Item *parent_item;
793   Eina_Object_Item *object_item;
794
795   if (!parent) return EINA_FALSE;
796   if (!object) return EINA_FALSE;
797   EINA_MAGIC_CHECK_CLASS(parent_class, EINA_FALSE);
798   EINA_MAGIC_CHECK_CLASS(object_class, EINA_FALSE);
799
800   if (!eina_lock_take(&parent_class->mutex))
801     {
802 #ifdef EINA_HAVE_DEBUG_THREADS
803       assert(pthread_equal(parent_class->self, pthread_self()));
804 #endif
805     }
806
807   if (!eina_lock_take(&object_class->mutex))
808     {
809 #ifdef EINA_HAVE_DEBUG_THREADS
810       assert(pthread_equal(object_class->self, pthread_self()));
811 #endif
812     }
813
814   parent_item = _eina_object_find_item(parent_class, parent);
815   if (!parent_item) return EINA_FALSE;
816
817   object_item = _eina_object_find_item(object_class, object);
818   if (!object_item) return EINA_FALSE;
819
820   if (object_item->parent)
821     object_item->parent->link = eina_inlist_remove(object_item->parent->link,
822                                                    EINA_INLIST_GET(object_item));
823
824   object_item->parent = parent_item;
825   parent_item->link = eina_inlist_append(parent_item->link,
826                                          EINA_INLIST_GET(object_item));
827
828   eina_lock_release(&parent_class->mutex);
829   eina_lock_release(&object_class->mutex);
830
831   return EINA_TRUE;
832 }
833
834 Eina_Object *
835 eina_object_parent_get(Eina_Class *class, Eina_Object *object)
836 {
837   Eina_Object_Item *object_item;
838   Eina_Object *or = NULL;
839
840   if (!object) return EINA_FALSE;
841   EINA_MAGIC_CHECK_CLASS(class, EINA_FALSE);
842
843   if (!eina_lock_take(&class->mutex))
844     {
845 #ifdef EINA_HAVE_DEBUG_THREADS
846       assert(pthread_equal(class->self, pthread_self()));
847 #endif
848     }
849
850   object_item = _eina_object_find_item(class, object);
851   if (object_item)
852     or = _eina_object_get(object_item->parent);
853
854   eina_lock_release(&class->mutex);
855
856   return or;
857 }
858