1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4
5 #if defined HAVE_DLADDR && ! defined _WIN32
6 # include <dlfcn.h>
7 #endif
8
9 #include <Eina.h>
10
11 #ifdef _WIN32
12 # include <evil_private.h> /* evil_time_get dladdr */
13 #endif
14
15 #if defined(__APPLE__) && defined(__MACH__)
16 # include <mach/mach_time.h>
17 #endif
18
19 #include "Eo.h"
20 #include "eo_ptr_indirection.h"
21 #include "eo_private.h"
22 #include "eo_add_fallback.h"
23
24 #include "eo_internal.h"
25
26 #include "efl_object_override.eo.c"
27 #ifdef HAVE_EXECINFO_H
28 #include <execinfo.h>
29 #endif
30
31 #ifdef HAVE_VALGRIND
32 # include <valgrind.h>
33 # include <memcheck.h>
34 #endif
35 static Eina_Bool _eo_trash_bypass = EINA_FALSE;
36
37 #define EO_CLASS_IDS_FIRST 1
38 #define EFL_OBJECT_OP_IDS_FIRST 1
39
40 /* Used inside the class_get functions of classes, see #EFL_DEFINE_CLASS */
41 EAPI Eina_Lock _efl_class_creation_lock;
42 EAPI unsigned int _efl_object_init_generation = 1;
43 int _eo_log_dom = -1;
44 Eina_Thread _efl_object_main_thread;
45 static unsigned int efl_del_api_generation = 0;
46 static Efl_Object_Op _efl_del_api_op_id = 0;
47 static Eina_Hash *class_overrides;
48
49 typedef enum _Eo_Ref_Op {
50 EO_REF_OP_NONE,
51 EO_REF_OP_NEW,
52 EO_REF_OP_FREE,
53 EO_REF_OP_REF,
54 EO_REF_OP_UNREF,
55 EO_REF_OP_REUSE,
56 } Eo_Ref_Op;
57
58 static inline void _eo_log_obj_init(void);
59 static inline void _eo_log_obj_shutdown(void);
60 static inline void _eo_log_obj_ref_op(const _Eo_Object *obj, Eo_Ref_Op ref_op);
61 #ifdef EO_DEBUG
62 #define EO_LOG_OBJS_BACKTRACE_MAX 1022
63 #define EO_LOG_OBJS_BACKTRACE_DEFAULT 62
64 static int _eo_log_objs_dom = -1;
65 static int _eo_log_objs_backtrace = EO_LOG_OBJS_BACKTRACE_DEFAULT; // 0 = enable tracking but no bt, N>0 = enable tracking and bt of size N
66 static Eo_Ref_Op _eo_log_objs_level = EO_REF_OP_NONE;
67 static Eina_Inarray _eo_log_objs_debug;
68 static Eina_Inarray _eo_log_objs_no_debug;
69 static double _eo_log_time_start;
70 static const char *_eo_ref_op_str[] = {
71 "ERROR",
72 "New ",
73 "Free ",
74 "Ref ",
75 "Unref",
76 "Reuse",
77 };
78 #ifdef HAVE_BACKTRACE
79 static Eina_Array _eo_log_objs;
80 static Eina_Spinlock _eo_log_objs_lock;
81 #endif
82 #else
_eo_log_obj_init(void)83 static inline void _eo_log_obj_init(void) { }
_eo_log_obj_shutdown(void)84 static inline void _eo_log_obj_shutdown(void) { }
_eo_log_obj_ref_op(const _Eo_Object * obj EINA_UNUSED,Eo_Ref_Op ref_op EINA_UNUSED)85 static inline void _eo_log_obj_ref_op(const _Eo_Object *obj EINA_UNUSED, Eo_Ref_Op ref_op EINA_UNUSED) { }
_eo_log_obj_report(const Eo_Id id EINA_UNUSED,int log_level EINA_UNUSED,const char * func_name EINA_UNUSED,const char * file EINA_UNUSED,int line EINA_UNUSED)86 void _eo_log_obj_report(const Eo_Id id EINA_UNUSED, int log_level EINA_UNUSED, const char *func_name EINA_UNUSED, const char *file EINA_UNUSED, int line EINA_UNUSED) { }
87 #endif
88
89 static _Efl_Class **_eo_classes = NULL;
90 static Eo_Id _eo_classes_last_id = 0;
91 static Eo_Id _eo_classes_alloc = 0;
92 static int _efl_object_init_count = 0;
93 static Eina_Hash *_ops_storage = NULL;
94 static Eina_Spinlock _ops_storage_lock;
95
96 static const Efl_Object_Optional efl_object_optional_cow_default = {};
97 Eina_Cow *efl_object_optional_cow = NULL;
98
99 static size_t _eo_sz = 0;
100 static size_t _eo_class_sz = 0;
101
102 static void _eo_condtor_reset(_Eo_Object *obj);
103 static inline void *_efl_data_scope_get(const _Eo_Object *obj, const _Efl_Class *klass);
104 static inline void *_efl_data_xref_internal(const char *file, int line, _Eo_Object *obj, const _Efl_Class *klass, const _Eo_Object *ref_obj);
105 static inline void _efl_data_xunref_internal(_Eo_Object *obj, void *data, const _Eo_Object *ref_obj);
106
107 static inline Efl_Object_Op _efl_object_api_op_id_get_internal(const void *api_func);
108
109 /* Start of Dich */
110
111
112 /* We are substracting the mask here instead of "AND"ing because it's a hot path,
113 * it should be a valid class at this point, and this lets the compiler do 1
114 * substraction at compile time. */
115 #define _UNMASK_ID(id) ((id) - MASK_CLASS_TAG)
116 #define ID_CLASS_GET(id) ({ \
117 (_Efl_Class *) (((_UNMASK_ID(id) <= _eo_classes_last_id) && (_UNMASK_ID(id) > 0)) ? \
118 (_eo_classes[_UNMASK_ID(id) - 1]) : NULL); \
119 })
120
121 #define EFL_OBJECT_OP_CLASS_PART(op) op >> 16
122 #define EFL_OBJECT_OP_FUNC_PART(op) op & 0xffff
123 #define EFL_OBJECT_OP_CREATE_OP_ID(class_id, func_id) ((unsigned short)class_id)<<16|((unsigned short)func_id&0xffff)
124
125 static const _Efl_Class *
_eo_op_class_get(Efl_Object_Op op)126 _eo_op_class_get(Efl_Object_Op op)
127 {
128 short class_id = EFL_OBJECT_OP_CLASS_PART(op);
129 return _eo_classes[class_id];
130 }
131 #if defined(DEBUG_VTABLE_ALLOCATION)
132 static int _allocated_memory = 0;
133
134 static inline void*
_vtable_alloc(unsigned long n,size_t elem)135 _vtable_alloc(unsigned long n, size_t elem)
136 {
137 _allocated_memory += n*elem;
138 return calloc(n, elem);
139 }
140 #else
141 static inline void*
_vtable_alloc(unsigned long n,size_t elem)142 _vtable_alloc(unsigned long n, size_t elem)
143 {
144 return calloc(n, elem);
145 }
146 #endif
147
148
149 /**
150 * This inits the vtable with a given size
151 */
152 static void
_vtable_init_size(Eo_Vtable * vtable,unsigned int size)153 _vtable_init_size(Eo_Vtable *vtable, unsigned int size)
154 {
155 //we assume here that _eo_classes_last_id was called before
156 vtable->size = size;
157 vtable->chain = _vtable_alloc(vtable->size, sizeof(Eo_Vtable_Node));
158 }
159
160 /**
161 * This inits the vtable wit hthe current size of allocated tables
162 */
163 static void
_vtable_init(Eo_Vtable * vtable)164 _vtable_init(Eo_Vtable *vtable)
165 {
166 //we assume here that _eo_classes_last_id was called before
167 _vtable_init_size(vtable, _eo_classes_last_id);
168 }
169
170 /**
171 * This removes all nodes from the klass that are copied from mro
172 */
173 static void
_vtable_mro_free(const _Efl_Class * klass)174 _vtable_mro_free(const _Efl_Class *klass)
175 {
176 const _Efl_Class **mro_itr = klass->mro;
177 const Eo_Vtable *vtable = &klass->vtable;
178 for ( ; *mro_itr ; mro_itr++)
179 {
180 const Eo_Vtable *mro_vtable = &(*mro_itr)->vtable;
181 if ((*mro_itr) == klass)
182 continue;
183 for (unsigned int i = 0; i < mro_vtable->size; ++i)
184 {
185 if (i == klass->class_id)
186 continue;
187 if (vtable->chain[i].funcs && mro_vtable->chain[i].funcs == vtable->chain[i].funcs)
188 {
189 vtable->chain[i].funcs = NULL;
190 }
191 }
192 }
193 }
194
195 static void
_vtable_free(Eo_Vtable * vtable,const Eo_Vtable * root)196 _vtable_free(Eo_Vtable *vtable, const Eo_Vtable *root)
197 {
198 if (root)
199 {
200 EINA_SAFETY_ON_FALSE_RETURN(vtable->size == root->size);
201 }
202
203 for (int i = 0; i < vtable->size; ++i)
204 {
205 if (root && root->chain[i].funcs == vtable->chain[i].funcs)
206 vtable->chain[i].count = 0;
207
208 if (vtable->chain[i].count)
209 {
210 free(vtable->chain[i].funcs);
211 }
212 }
213 free(vtable->chain);
214 }
215
216 /**
217 * This takes over all set chains of the src to dest.
218 * This should only be called on Eo_Vtables, which are initialized with this value.
219 * Previous setted values are going to be overwritten.
220 */
221 static void
_vtable_take_over(Eo_Vtable * dest,const Eo_Vtable * src)222 _vtable_take_over(Eo_Vtable *dest, const Eo_Vtable *src)
223 {
224 for (int i = 0; i < src->size; ++i)
225 {
226 if (src->chain[i].funcs)
227 {
228 dest->chain[i] = src->chain[i];
229 }
230 }
231 }
232
233 /**
234 * Fills the node of the passed class id with a empty none NULL pointer.
235 * This is used to indicate that a specific node has a normal 0 size, but is set.
236 */
237 static void
_vtable_insert_empty_funcs(Eo_Vtable * vtable,unsigned short class_id)238 _vtable_insert_empty_funcs(Eo_Vtable *vtable, unsigned short class_id)
239 {
240 vtable->chain[class_id].funcs = (void*)0x1010101;
241 vtable->chain[class_id].count = 0;
242 }
243
244 /**
245 * duplicate the source node, and write the duplicated values to the destination
246 * No logical changes are applied to src.
247 */
248 static void
_vtable_copy_node(Eo_Vtable_Node * dest,const Eo_Vtable_Node * src)249 _vtable_copy_node(Eo_Vtable_Node *dest, const Eo_Vtable_Node *src)
250 {
251 dest->count = src->count;
252 dest->funcs = _vtable_alloc(sizeof(op_type_funcs), src->count);
253 memcpy(dest->funcs, src->funcs, sizeof(op_type_funcs) * src->count);
254 }
255
256 /**
257 * Initialize a node with a empty funcs array of the passed length
258 */
259 static void
_vtable_prepare_empty_node(Eo_Vtable * dest,unsigned int length,unsigned int class_id)260 _vtable_prepare_empty_node(Eo_Vtable *dest, unsigned int length, unsigned int class_id)
261 {
262 dest->chain[class_id].count = length;
263 dest->chain[class_id].funcs = _vtable_alloc(sizeof(op_type_funcs), dest->chain[class_id].count);
264 }
265
266 /**
267 * Copy all setted APIs from src to dest.
268 * Already set function slots are going to be replaced.
269 */
270 static void
_vtable_merge_defined_api(Eo_Vtable * dest,const Eo_Vtable * src,Eina_Bool * hitmap)271 _vtable_merge_defined_api(Eo_Vtable *dest, const Eo_Vtable *src, Eina_Bool *hitmap)
272 {
273 for (unsigned int i = 0; i < src->size; ++i)
274 {
275 //if there is a source node evalulate if we need to copy it
276 if (src->chain[i].funcs)
277 {
278 if (!dest->chain[i].funcs)
279 {
280 dest->chain[i] = src->chain[i];
281 EINA_SAFETY_ON_FALSE_RETURN(hitmap[i] == EINA_FALSE);
282 }
283 else
284 {
285 if (!hitmap[i])
286 {
287 const Eo_Vtable_Node node = dest->chain[i];
288 if (!node.count)
289 _vtable_insert_empty_funcs(dest, i);
290 else
291 _vtable_copy_node(&dest->chain[i], &node); //we copy what we have, and overwrite in the later for loop
292 hitmap[i] = EINA_TRUE;
293 }
294 for (int j = 0; j < src->chain[i].count; ++j)
295 {
296 if (src->chain[i].funcs[j].func)
297 dest->chain[i].funcs[j] = src->chain[i].funcs[j];
298 }
299 }
300 }
301 }
302 }
303
304 /**
305 * Ensure that all set nodes from src are also set on dest.
306 * No real values are copied, the newly taken or allocated slots will be empty.
307 */
308 static void
_vtable_merge_empty(Eo_Vtable * dest,const Eo_Vtable * src,Eina_Bool * hitmap)309 _vtable_merge_empty(Eo_Vtable *dest, const Eo_Vtable *src, Eina_Bool *hitmap)
310 {
311 for (unsigned int i = 0; i < src->size; ++i)
312 {
313 if (src->chain[i].funcs && !dest->chain[i].funcs)
314 {
315 if (!src->chain[i].count)
316 {
317 dest->chain[i].funcs = src->chain[i].funcs;
318 dest->chain[i].count = src->chain[i].count;
319 }
320 else
321 {
322 _vtable_prepare_empty_node(dest, src->chain[i].count, i);
323 hitmap[i] = EINA_TRUE;
324 }
325 }
326 }
327 }
328
329 static inline const op_type_funcs *
_vtable_func_get(const Eo_Vtable * vtable,Efl_Object_Op op)330 _vtable_func_get(const Eo_Vtable *vtable, Efl_Object_Op op)
331 {
332 unsigned short class_id = EFL_OBJECT_OP_CLASS_PART(op);
333 unsigned short func_id = EFL_OBJECT_OP_FUNC_PART(op);
334
335 if (EINA_UNLIKELY(vtable->size <= class_id))
336 return NULL;
337 if (EINA_UNLIKELY(vtable->chain[class_id].count <= func_id))
338 return NULL;
339
340 return &vtable->chain[class_id].funcs[func_id];
341 }
342
343 static inline Eina_Bool
_vtable_func_set(Eo_Vtable * vtable,const _Efl_Class * klass,const _Efl_Class * hierarchy_klass,Efl_Object_Op op,Eo_Op_Func_Type func,Eina_Bool allow_same_override)344 _vtable_func_set(Eo_Vtable *vtable, const _Efl_Class *klass,
345 const _Efl_Class *hierarchy_klass, Efl_Object_Op op,
346 Eo_Op_Func_Type func, Eina_Bool allow_same_override)
347 {
348 op_type_funcs *fsrc;
349 unsigned short class_id = EFL_OBJECT_OP_CLASS_PART(op);
350 unsigned short func_id = EFL_OBJECT_OP_FUNC_PART(op);
351 Eo_Vtable_Node *hirachy_node = NULL;
352 Eo_Vtable_Node *node = NULL;
353
354 EINA_SAFETY_ON_FALSE_RETURN_VAL(vtable->size >= class_id, EINA_FALSE);
355
356 if (klass->parent && klass->parent->vtable.size > class_id)
357 hirachy_node = &klass->parent->vtable.chain[class_id];
358 if (hierarchy_klass)
359 hirachy_node = &hierarchy_klass->vtable.chain[class_id];
360 node = &vtable->chain[class_id];
361
362 EINA_SAFETY_ON_NULL_RETURN_VAL(node->funcs, EINA_FALSE);
363 EINA_SAFETY_ON_FALSE_RETURN_VAL(node->count >= func_id, EINA_FALSE);
364 fsrc = &node->funcs[func_id];
365
366 if (hierarchy_klass && !func)
367 {
368 if (!func)
369 {
370 op_type_funcs funcs = hirachy_node->funcs[func_id];
371 klass = funcs.src;
372 func = funcs.func;
373 }
374 }
375 else
376 {
377 if (!allow_same_override && (fsrc->src == klass))
378 {
379 const _Efl_Class *op_kls = _eo_op_class_get(op);
380 ERR("Class '%s': Overriding already set func %p for op %d (%s) with %p.",
381 klass->desc->name, fsrc->func, op, op_kls->desc->name, func);
382 return EINA_FALSE;
383 }
384 }
385
386 fsrc->src = klass;
387 fsrc->func = func;
388
389 return EINA_TRUE;
390 }
391
392 /* END OF DICH */
393
394 #define _EO_ID_GET(Id) ((Eo_Id) (Id))
395
396
397 static inline Eina_Bool
_eo_is_a_obj(const Eo * eo_id)398 _eo_is_a_obj(const Eo *eo_id)
399 {
400 Eo_Id oid = (Eo_Id) _EO_ID_GET(eo_id);
401 return !!(oid & MASK_OBJ_TAG);
402 }
403
404 static inline Eina_Bool
_eo_is_a_class(const Eo * eo_id)405 _eo_is_a_class(const Eo *eo_id)
406 {
407 Eo_Id oid = (Eo_Id) _EO_ID_GET(eo_id);
408 return !!(oid & MASK_CLASS_TAG);
409 }
410
411 static inline _Efl_Class *
_eo_class_pointer_get(const Efl_Class * klass_id)412 _eo_class_pointer_get(const Efl_Class *klass_id)
413 {
414 return ID_CLASS_GET((Eo_Id)klass_id);
415 }
416
417 static const char *
_eo_op_desc_name_get(const Efl_Op_Description * desc)418 _eo_op_desc_name_get(const Efl_Op_Description *desc)
419 {
420 static const char *fct_name = "unknown";
421
422 if (!desc)
423 {
424 return fct_name;
425 }
426
427 #ifndef _WIN32
428 # ifdef HAVE_DLADDR
429 static Dl_info info;
430 if (dladdr(desc->api_func, &info) != 0)
431 fct_name = info.dli_sname;
432 # endif
433 #else
434 fct_name = desc->api_func; /* Same on windows */
435 #endif
436 return fct_name;
437 }
438
439 static inline const op_type_funcs *
_eo_kls_itr_next(const _Efl_Class * orig_kls,const _Efl_Class * cur_klass,Efl_Object_Op op,Eina_Bool super)440 _eo_kls_itr_next(const _Efl_Class *orig_kls, const _Efl_Class *cur_klass,
441 Efl_Object_Op op, Eina_Bool super)
442 {
443 const _Efl_Class **kls_itr = NULL;
444
445 /* Find the kls itr. */
446 kls_itr = orig_kls->mro;
447 while (*kls_itr && (*kls_itr != cur_klass))
448 kls_itr++;
449
450 if (*kls_itr)
451 {
452 if (super) kls_itr++;
453 while (*kls_itr)
454 {
455 const op_type_funcs *fsrc = _vtable_func_get(&(*kls_itr)->vtable, op);
456 if (!fsrc || !fsrc->func)
457 {
458 kls_itr++;
459 continue;
460 }
461 return fsrc;
462 }
463 }
464
465 return NULL;
466 }
467
468 static inline void
_apply_auto_unref(_Eo_Object * obj,const Eo * eo_obj)469 _apply_auto_unref(_Eo_Object *obj, const Eo *eo_obj)
470 {
471 if (EINA_UNLIKELY(obj && obj->auto_unref))
472 {
473 if (obj->finalized && !(--obj->auto_unref))
474 efl_unref(eo_obj);
475 }
476 }
477
478 /************************************ EO ************************************/
479
480 static EFL_FUNC_TLS _Efl_Class *_super_klass = NULL;
481
482 static Eo *
_efl_super_cast(const Eo * eo_id,const Efl_Class * cur_klass,Eina_Bool super)483 _efl_super_cast(const Eo *eo_id, const Efl_Class *cur_klass, Eina_Bool super)
484 {
485 EO_CLASS_POINTER_GOTO(cur_klass, super_klass, err);
486
487 #ifdef EO_DEBUG
488 if (EINA_UNLIKELY(!_eo_is_a_obj(eo_id) && !_eo_is_a_class(eo_id))) goto err_obj;
489 #endif
490
491 if (EINA_UNLIKELY(!_eo_is_a_obj(eo_id)))
492 goto do_klass;
493
494 #ifndef EO_DEBUG
495 if (!super && EINA_UNLIKELY(!efl_isa(eo_id, cur_klass)))
496 #else
497 if (EINA_UNLIKELY(!efl_isa(eo_id, cur_klass)))
498 #endif
499 goto err_obj_hierarchy;
500
501 EO_OBJ_POINTER_RETURN_VAL(eo_id, obj, NULL);
502 obj->cur_klass = super_klass;
503 obj->super = super;
504 EO_OBJ_DONE(eo_id);
505
506 return (Eo *) eo_id;
507
508 do_klass:
509 // efl_super(Class) is extremely rarely used, so TLS write is fine
510 EINA_SAFETY_ON_FALSE_RETURN_VAL(super, NULL);
511 _super_klass = super_klass;
512 return (Eo *) eo_id;
513
514 err:
515 _EO_POINTER_ERR(cur_klass, "Class (%p) is an invalid ref.", cur_klass);
516 return NULL;
517 #ifdef EO_DEBUG
518 err_obj:
519 _EO_POINTER_ERR(eo_id, "Object (%p) is an invalid ref, class=%p (%s).", eo_id, cur_klass, efl_class_name_get(cur_klass));
520 return NULL;
521 #endif
522 err_obj_hierarchy:
523 _EO_POINTER_ERR(eo_id, "Object (%p) class=%p (%s) is not an instance of class=%p (%s).", eo_id, efl_class_get(eo_id), efl_class_name_get(eo_id), cur_klass, efl_class_name_get(cur_klass));
524 return NULL;
525 }
526
527 EAPI Eo *
efl_super(const Eo * eo_id,const Efl_Class * cur_klass)528 efl_super(const Eo *eo_id, const Efl_Class *cur_klass)
529 {
530 return _efl_super_cast(eo_id, cur_klass, EINA_TRUE);
531 }
532
533 EAPI Eo *
efl_cast(const Eo * eo_id,const Efl_Class * cur_klass)534 efl_cast(const Eo *eo_id, const Efl_Class *cur_klass)
535 {
536 return _efl_super_cast(eo_id, cur_klass, EINA_FALSE);
537 }
538
539 EAPI Eina_Bool
_efl_object_call_resolve(Eo * eo_id,const char * func_name,Efl_Object_Op_Call_Data * call,Efl_Object_Op op,const char * file,int line)540 _efl_object_call_resolve(Eo *eo_id, const char *func_name, Efl_Object_Op_Call_Data *call, Efl_Object_Op op, const char *file, int line)
541 {
542 const _Efl_Class *klass, *main_klass;
543 const _Efl_Class *cur_klass = NULL;
544 _Eo_Object *obj = NULL;
545 const Eo_Vtable *vtable = NULL;
546 const op_type_funcs *func;
547 Eina_Bool super = EINA_TRUE;
548
549 if (EINA_UNLIKELY(!eo_id)) goto on_null;
550
551
552 EO_OBJ_POINTER_RETURN_VAL_PROXY(eo_id, _obj, EINA_FALSE);
553
554 obj = _obj;
555 klass = _obj->klass;
556 vtable = EO_VTABLE2(obj);
557 if (EINA_UNLIKELY(_obj->cur_klass != NULL))
558 {
559 // YES this is a goto with a label to return. this is a
560 // micro-optimization to move infrequent code out of the
561 // hot path of the function
562 goto obj_super;
563 }
564 obj_super_back:
565 _efl_ref(_obj);
566
567 main_klass = klass;
568
569 /* If we have a current class, we need to itr to the next. */
570 if (cur_klass)
571 {
572 // YES this is a goto with a label to return. this is a
573 // micro-optimization to move infrequent code out of the
574 // hot path of the function
575 goto ok_cur_klass;
576 }
577 else
578 {
579 func = _vtable_func_get(vtable, op);
580 EINA_PREFETCH_NOCACHE(func);
581 // this is not very likely to happen - but may if its an invalid
582 // call or a composite object, but either way, it's not very likely
583 // so make it a goto to save on instruction cache
584 if (!func) goto end;
585 }
586 ok_cur_klass_back:
587
588 if (EINA_LIKELY(func->func && func->src))
589 {
590 call->eo_id = eo_id;
591 call->obj = obj;
592 call->func = func->func;
593 call->data = _efl_data_scope_get(obj, func->src);
594
595 return EINA_TRUE;
596 }
597
598 // very unlikely in general to use a goto to move code out of l1 cache
599 // ie instruction cache
600 if (func->src != NULL) goto err_func_src;
601
602 end:
603 /* Try composite objects */
604 {
605 Eina_List *itr;
606 Eo *emb_obj_id;
607 EINA_LIST_FOREACH(obj->opt->composite_objects, itr, emb_obj_id)
608 {
609 EO_OBJ_POINTER_PROXY(emb_obj_id, emb_obj);
610 if (EINA_UNLIKELY(!emb_obj)) continue;
611
612 func = _vtable_func_get(&emb_obj->klass->vtable, op);
613 if (func == NULL) goto composite_continue;
614
615 if (EINA_LIKELY(func->func && func->src))
616 {
617 call->eo_id = _eo_obj_id_get(emb_obj);
618 call->obj = _efl_ref(emb_obj);
619 call->func = func->func;
620 call->data = _efl_data_scope_get(emb_obj, func->src);
621 /* We reffed it above, but no longer need/use it. */
622 _efl_unref(obj);
623 EO_OBJ_DONE(emb_obj_id);
624 return EINA_TRUE;
625 }
626 composite_continue:
627 EO_OBJ_DONE(emb_obj_id);
628 }
629 }
630
631 // all of this is error handling at the end so... rare-ish
632 // If it's a do_super call.
633 if (cur_klass)
634 {
635 ERR("in %s:%d: func '%s' (%d) could not be resolved on %s for class '%s' for super of '%s'.",
636 file, line, func_name, op, efl_debug_name_get(eo_id), main_klass->desc->name,
637 cur_klass->desc->name);
638 goto err;
639 }
640 else
641 {
642 /* we should not be able to take this branch */
643 ERR("in %s:%d: func '%s' (%d) could not be resolved on %s for class '%s'.",
644 file, line, func_name, op, efl_debug_name_get(eo_id), main_klass->desc->name);
645 goto err;
646 }
647
648 err_func_src:
649 ERR("in %s:%d: you called a pure virtual func '%s' (%d) of class '%s'.",
650 file, line, func_name, op, klass->desc->name);
651 err:
652 _apply_auto_unref(obj, eo_id);
653 _efl_unref(obj);
654 _eo_obj_pointer_done((Eo_Id)eo_id);
655
656 return EINA_FALSE;
657
658 // yes - special "move out of hot path" code blobs with goto's for
659 // speed reasons to have intr prefetches work better and miss less
660 ok_cur_klass:
661 func = _eo_kls_itr_next(klass, cur_klass, op, super);
662 if (!func) goto end;
663 klass = func->src;
664 goto ok_cur_klass_back;
665
666 obj_super:
667 {
668 cur_klass = obj->cur_klass;
669 super = obj->super;
670 obj->cur_klass = NULL;
671
672 if (_obj_is_override(obj) && cur_klass && super &&
673 (_eo_class_id_get(cur_klass) == EFL_OBJECT_OVERRIDE_CLASS))
674 {
675 /* Doing a efl_super(obj, EFL_OBJECT_OVERRIDE_CLASS) should
676 * result in calling as if it's a normal class. */
677 vtable = &klass->vtable;
678 cur_klass = NULL;
679 }
680
681 }
682 goto obj_super_back;
683
684 on_null:
685 if (EINA_UNLIKELY(efl_del_api_generation != _efl_object_init_generation))
686 {
687 _efl_del_api_op_id = _efl_object_api_op_id_get_internal(EFL_FUNC_COMMON_OP_FUNC(efl_del));
688 efl_del_api_generation = _efl_object_init_generation;
689 }
690 if (op != _efl_del_api_op_id)
691 WRN("NULL passed to function %s().", func_name);
692 return EINA_FALSE;
693 }
694
695 EAPI void
_efl_object_call_end(Efl_Object_Op_Call_Data * call)696 _efl_object_call_end(Efl_Object_Op_Call_Data *call)
697 {
698 if (EINA_LIKELY(!!call->obj))
699 {
700 _apply_auto_unref(call->obj, call->eo_id);
701 _efl_unref(call->obj);
702 _eo_obj_pointer_done((Eo_Id)call->eo_id);
703 }
704 }
705
706 static inline Eina_Bool
_eo_api_func_equal(const void * api_func1,const void * api_func2)707 _eo_api_func_equal(const void *api_func1, const void *api_func2)
708 {
709 #ifndef _WIN32
710 return (api_func1 == api_func2);
711 #else
712 /* On Windows, DLL API's will be exported using the dllexport flag.
713 * When used by another library or executable, they will be declared
714 * using the dllimport flag. What happens really is that two symbols are
715 * created, at two different addresses. So it's impossible to match
716 * them. We fallback to plain string comparison based on the
717 * function name itself. Slow, but this should rarely happen.
718 */
719 return (api_func2 && api_func1 && !strcmp(api_func2, api_func1));
720 #endif
721 }
722
723 static inline Efl_Object_Op
_efl_object_api_op_id_get_internal(const void * api_func)724 _efl_object_api_op_id_get_internal(const void *api_func)
725 {
726 eina_spinlock_take(&_ops_storage_lock);
727 #ifndef _WIN32
728 Efl_Object_Op op = (uintptr_t) eina_hash_find(_ops_storage, &api_func);
729 #else
730 Efl_Object_Op op = (uintptr_t) eina_hash_find(_ops_storage, api_func);
731 #endif
732 eina_spinlock_release(&_ops_storage_lock);
733
734 return op;
735 }
736
737 /* LEGACY, should be removed before next release */
738 EAPI Efl_Object_Op
_efl_object_api_op_id_get(const void * api_func)739 _efl_object_api_op_id_get(const void *api_func)
740 {
741 Efl_Object_Op op = _efl_object_api_op_id_get_internal(api_func);
742
743 if (op == EFL_NOOP)
744 {
745 ERR("Unable to resolve op for api func %p", api_func);
746 }
747
748 return op;
749 }
750
751 EAPI Efl_Object_Op
_efl_object_op_api_id_get(const void * api_func,const Eo * eo_obj,const char * api_func_name,const char * file,int line)752 _efl_object_op_api_id_get(const void *api_func, const Eo *eo_obj, const char *api_func_name, const char *file, int line)
753 {
754 Efl_Object_Op op;
755
756 #ifndef EO_DEBUG
757 if (!eo_obj) return EFL_NOOP;
758 #endif
759 op = _efl_object_api_op_id_get_internal(api_func);
760 if (op == EFL_NOOP)
761 {
762 EO_OBJ_POINTER(eo_obj, obj);
763 eina_log_print(_eo_log_dom, EINA_LOG_LEVEL_ERR,
764 file, api_func_name, line,
765 "Unable to resolve op for api func %p for obj=%p (%s)",
766 api_func, eo_obj, efl_class_name_get(eo_obj));
767 _apply_auto_unref(obj, eo_obj);
768 return EFL_NOOP;
769 }
770
771 return op;
772 }
773
774 /* klass is the klass we are working on. hierarchy_klass is the class whe should
775 * use when validating. */
776 static Eina_Bool
_eo_class_funcs_set(Eo_Vtable * vtable,const Efl_Object_Ops * ops,const _Efl_Class * hierarchy_klass,const _Efl_Class * klass,Eina_Bool override_only,unsigned int class_id,Eina_Bool * hitmap)777 _eo_class_funcs_set(Eo_Vtable *vtable, const Efl_Object_Ops *ops, const _Efl_Class *hierarchy_klass, const _Efl_Class *klass, Eina_Bool override_only, unsigned int class_id, Eina_Bool *hitmap)
778 {
779 unsigned int i, j;
780 unsigned int number_of_new_functions = 0;
781 const Efl_Op_Description *op_desc;
782 const Efl_Op_Description *op_descs;
783 const _Efl_Class *override_class;
784 const void **api_funcs;
785 Eina_Bool check_equal;
786
787 op_descs = ops->descs;
788 override_class = override_only ? hierarchy_klass : NULL;
789
790 DBG("Set functions for class '%s':%p", klass->desc->name, klass);
791
792 if (!override_only)
793 _vtable_insert_empty_funcs(vtable, class_id);
794 if (!op_descs || !ops->count)
795 return EINA_TRUE;
796
797 #ifdef EO_DEBUG
798 check_equal = EINA_TRUE;
799 #else
800 check_equal = !override_only;
801 #endif
802 api_funcs = alloca(ops->count * sizeof(api_funcs[0]));
803
804 /* sanity checks */
805 for (i = 0, op_desc = op_descs; i < ops->count; i++, op_desc++)
806 {
807 if (op_desc->api_func == NULL)
808 {
809 ERR("Class '%s': NULL API not allowed (NULL->%p '%s').",
810 klass->desc->name, op_desc->func, _eo_op_desc_name_get(op_desc));
811 return EINA_FALSE;
812 }
813
814 if (check_equal)
815 {
816 for (j = 0; j < i; j++)
817 {
818 if (_eo_api_func_equal(op_desc->api_func, api_funcs[j]))
819 {
820 ERR("Class '%s': API previously defined (%p->%p '%s').",
821 klass->desc->name, op_desc->api_func, op_desc->func, _eo_op_desc_name_get(op_desc));
822 return EINA_FALSE;
823 }
824 }
825
826 api_funcs[i] = op_desc->api_func;
827 }
828 if (_efl_object_api_op_id_get_internal(op_desc->api_func) == EFL_NOOP)
829 {
830 number_of_new_functions ++;
831 }
832 }
833
834 if (!override_only)
835 {
836 if (number_of_new_functions)
837 {
838 //Before setting any real functions, allocate the node that will contain all the functions
839 _vtable_prepare_empty_node(vtable, number_of_new_functions, class_id);
840 }
841 hitmap[class_id] = EINA_TRUE;
842 }
843
844 for (i = 0, j = 0, op_desc = op_descs; i < ops->count; i++, op_desc++)
845 {
846 Efl_Object_Op op2 = EFL_NOOP;
847 short op2_class_id;
848
849 /* Get the opid for the function. */
850 op2 = _efl_object_api_op_id_get_internal(op_desc->api_func);
851
852 if (op2 == EFL_NOOP)
853 {
854 //functions that do not have a op yet, are considered to be belonging to this class
855 if (override_only)
856 {
857 ERR("Class '%s': Tried overriding a previously undefined function.", klass->desc->name);
858 return EINA_FALSE;
859 }
860
861 op2 = EFL_OBJECT_OP_CREATE_OP_ID(class_id, j);
862 eina_spinlock_take(&_ops_storage_lock);
863 #ifndef _WIN32
864 eina_hash_add(_ops_storage, &op_desc->api_func, (void *) (uintptr_t) op2);
865 #else
866 eina_hash_add(_ops_storage, op_desc->api_func, (void *) (uintptr_t) op2);
867 #endif
868 eina_spinlock_release(&_ops_storage_lock);
869 j ++;
870 }
871
872 #ifdef EO_DEBUG
873 DBG("%p->%p '%s'", op_desc->api_func, op_desc->func, _eo_op_desc_name_get(op_desc));
874 #endif
875 op2_class_id = EFL_OBJECT_OP_CLASS_PART(op2);
876 //in case we are having a function overwrite for a specific type, copy the relevant vtable
877 if (!hitmap[op2_class_id])
878 {
879 const Eo_Vtable_Node node = vtable->chain[op2_class_id];
880 _vtable_copy_node(&vtable->chain[op2_class_id], &node);
881 hitmap[op2_class_id] = EINA_TRUE;
882 }
883 if (!_vtable_func_set(vtable, klass, override_class, op2, op_desc->func, EINA_TRUE))
884 return EINA_FALSE;
885 }
886 return EINA_TRUE;
887 }
888
889 EAPI Eina_Bool
efl_class_functions_set(const Efl_Class * klass_id,const Efl_Object_Ops * object_ops,const Efl_Object_Property_Reflection_Ops * reflection_table)890 efl_class_functions_set(const Efl_Class *klass_id, const Efl_Object_Ops *object_ops, const Efl_Object_Property_Reflection_Ops *reflection_table)
891 {
892 EO_CLASS_POINTER_GOTO(klass_id, klass, err_klass);
893 Efl_Object_Ops empty_ops = { 0 };
894 Eina_Bool *hitmap;
895
896 // not likely so use goto to alleviate l1 instruction cache of rare code
897 if (klass->functions_set) goto err_funcs;
898 klass->functions_set = EINA_TRUE;
899
900 if (!object_ops) object_ops = &empty_ops;
901
902 klass->reflection = reflection_table;
903
904 klass->ops_count = object_ops->count;
905
906 klass->class_id = _UNMASK_ID(klass->header.id) - 1;
907
908 _vtable_init(&klass->vtable);
909 if (!klass->vtable.chain) goto err_vtable;
910
911 hitmap = alloca(klass->vtable.size);
912 memset(hitmap, 0, klass->vtable.size);
913 /* Merge in all required vtable entries */
914 {
915 const _Efl_Class **mro_itr = klass->mro;
916 /* take over everything from the parent */
917 if (klass->parent)
918 {
919 _vtable_take_over(&klass->vtable, &klass->parent->vtable);
920 }
921 /*
922 * - jump to the mro entry containing the parent
923 * - everything further from the parent to the next elements is already
924 * represented in the vtable of the parent.
925 */
926 for ( ; *mro_itr ; mro_itr++)
927 {
928 if (*mro_itr == klass->parent)
929 break;
930 }
931 /**
932 * merge in all the APIs that are extended in the current klass for this first time.
933 * That means, they are not extended anywhere from the parent further up.
934 */
935 for ( mro_itr-- ; mro_itr > klass->mro ; mro_itr--)
936 {
937 _vtable_merge_defined_api(&klass->vtable, &(*mro_itr)->vtable, hitmap);
938 }
939 /*
940 * add slots for the interfaces and mixins we are inheriting from
941 */
942 for (int i = 0; klass->extensions[i]; i++)
943 {
944 const _Efl_Class *ext = klass->extensions[i];
945 /*for all extensions of the class, ensure that *at least* empty vtables are available, so the efl_isa calls do succeed*/
946 _vtable_merge_empty(&klass->vtable, &ext->vtable, hitmap);
947 }
948 }
949 {
950 unsigned int i;
951
952 for (i = 0; i < object_ops->count; i++)
953 {
954 Efl_Object_Op op = _efl_object_api_op_id_get_internal(object_ops->descs[i].api_func);
955 if (op == EFL_NOOP) continue; //EFL_NOOP means that this function is not yet defined, this will be handled later
956 short class_id = EFL_OBJECT_OP_CLASS_PART(op);
957 if (klass->vtable.chain[class_id].count == 0)
958 {
959 const _Efl_Class *required_klass = _eo_classes[class_id];
960 /* in case this type is not already inherited, error on everything that is not a mixin */
961 if (klass->desc->type == EFL_CLASS_TYPE_MIXIN)
962 {
963 /* this is when a mixin implemets a regular api, we just prepare a empty node, the rest will be implemented later */
964 _vtable_prepare_empty_node(&klass->vtable, required_klass->vtable.chain[class_id].count, class_id);
965 hitmap[class_id] = EINA_TRUE;
966 }
967 else
968 {
969 ERR("There is an API implemented, whoms type is not part of this class. %s vs. %s", klass->desc->name, required_klass->desc->name);
970 _vtable_prepare_empty_node(&klass->vtable, required_klass->vtable.chain[class_id].count, class_id);
971 hitmap[class_id] = EINA_TRUE;
972 }
973
974 }
975 }
976 }
977 return _eo_class_funcs_set(&klass->vtable, object_ops, klass, klass, EINA_FALSE, klass->class_id, hitmap);
978 err_funcs:
979 ERR("Class %s already had its functions set..", klass->desc->name);
980 return EINA_FALSE;
981 err_klass:
982 _EO_POINTER_ERR(klass_id, "Class (%p) is an invalid ref.", klass_id);
983 return EINA_FALSE;
984 err_vtable:
985 ERR("failed to allocate vtable for class '%s'", klass->desc->name);
986 return EINA_FALSE;
987 }
988
989 static Eo *
_efl_add_internal_start_do(const char * file,int line,const Efl_Class * klass_id,Eo * parent_id,Eina_Bool ref,Eina_Bool is_fallback,Efl_Substitute_Ctor_Cb substitute_ctor,void * sub_ctor_data)990 _efl_add_internal_start_do(const char *file, int line, const Efl_Class *klass_id, Eo *parent_id, Eina_Bool ref, Eina_Bool is_fallback, Efl_Substitute_Ctor_Cb substitute_ctor, void *sub_ctor_data)
991 {
992 const char *func_name = __func__;
993 _Eo_Object *obj;
994 Eo_Stack_Frame *fptr = NULL;
995
996 if (is_fallback) fptr = _efl_add_fallback_stack_push(NULL);
997
998 if (class_overrides)
999 {
1000 const Efl_Class *override = eina_hash_find(class_overrides, &klass_id);
1001 if (override) klass_id = override;
1002 }
1003
1004 EO_CLASS_POINTER_GOTO_PROXY(klass_id, klass, err_klass);
1005
1006 // Check that in the case of efl_add we do pass a parent.
1007 if (!ref && !parent_id)
1008 ERR("Creation of '%s' object at line %i in '%s' is done without parent. This should use efl_add_ref.",
1009 klass->desc->name, line, file);
1010
1011 if (parent_id)
1012 {
1013 EO_OBJ_POINTER_GOTO_PROXY(parent_id, parent, err_parent);
1014 }
1015
1016 // not likely so use goto to alleviate l1 instruction cache of rare code
1017 if (EINA_UNLIKELY(klass->desc->type != EFL_CLASS_TYPE_REGULAR))
1018 goto err_noreg;
1019
1020 eina_spinlock_take(&klass->objects.trash_lock);
1021 obj = eina_trash_pop(&klass->objects.trash);
1022 if (obj)
1023 {
1024 memset(obj, 0, klass->obj_size);
1025 klass->objects.trash_count--;
1026 }
1027 else
1028 {
1029 obj = calloc(1, klass->obj_size);
1030 }
1031 eina_spinlock_release(&klass->objects.trash_lock);
1032
1033 obj->opt = eina_cow_alloc(efl_object_optional_cow);
1034 _efl_ref(obj);
1035 obj->klass = klass;
1036
1037 obj->header.id = _eo_id_allocate(obj, parent_id);
1038 Eo *eo_id = _eo_obj_id_get(obj);
1039
1040 _eo_log_obj_ref_op(obj, EO_REF_OP_NEW);
1041
1042 _eo_condtor_reset(obj);
1043
1044 efl_ref(eo_id);
1045
1046 /* Reference for the parent if is_ref is done in _efl_add_end */
1047 if (parent_id) efl_parent_set(eo_id, parent_id);
1048
1049 /* eo_id can change here. Freeing is done on the resolved object. */
1050 if (!substitute_ctor) eo_id = efl_constructor(eo_id);
1051 else eo_id = substitute_ctor(sub_ctor_data, eo_id);
1052 // not likely so use goto to alleviate l1 instruction cache of rare code
1053 if (!eo_id) goto err_noid;
1054 // not likely so use goto to alleviate l1 instruction cache of rare code
1055 else if (eo_id != _eo_obj_id_get(obj)) goto ok_nomatch;
1056 ok_nomatch_back:
1057 if (is_fallback) fptr->obj = eo_id;
1058 if (parent_id) EO_OBJ_DONE(parent_id);
1059 return eo_id;
1060
1061 ok_nomatch:
1062 {
1063 EO_OBJ_POINTER_GOTO_PROXY(eo_id, new_obj, err_newid);
1064 _efl_ref(new_obj);
1065 efl_ref(eo_id);
1066 /* We might have two refs on the old object at this point. */
1067 efl_parent_set((Eo *) obj->header.id, NULL);
1068 efl_unref(_eo_obj_id_get(obj));
1069 _efl_unref(obj);
1070 EO_OBJ_DONE(eo_id);
1071 }
1072 goto ok_nomatch_back;
1073
1074 err_noid:
1075 ERR("in %s:%d: Object of class '%s' - Error while constructing object",
1076 file, line, klass->desc->name);
1077 /* We might have two refs at this point. */
1078 efl_parent_set((Eo *) obj->header.id, NULL);
1079 efl_unref(_eo_obj_id_get(obj));
1080 _efl_unref(obj);
1081 err_newid:
1082 if (parent_id) EO_OBJ_DONE(parent_id);
1083 return NULL;
1084 err_noreg:
1085 ERR("in %s:%d: Class '%s' is not instantiate-able. Aborting.", file, line, klass->desc->name);
1086 if (parent_id) EO_OBJ_DONE(parent_id);
1087 return NULL;
1088
1089 err_klass:
1090 _EO_POINTER_ERR(klass_id, "in %s:%d: Class (%p) is an invalid ref.", file, line, klass_id);
1091 err_parent:
1092 return NULL;
1093 }
1094
1095 EAPI Eo *
_efl_add_internal_start(const char * file,int line,const Efl_Class * klass_id,Eo * parent_id,Eina_Bool ref,Eina_Bool is_fallback)1096 _efl_add_internal_start(const char *file, int line, const Efl_Class *klass_id, Eo *parent_id, Eina_Bool ref, Eina_Bool is_fallback)
1097 {
1098 return _efl_add_internal_start_do(file, line, klass_id, parent_id, ref, is_fallback, NULL, NULL);
1099 }
1100
_efl_add_internal_start_bindings(const char * file,int line,const Efl_Class * klass_id,Eo * parent_id,Eina_Bool ref,Eina_Bool is_fallback,Efl_Substitute_Ctor_Cb substitute_ctor,void * sub_ctor_data)1101 EAPI Eo * _efl_add_internal_start_bindings(const char *file, int line, const Efl_Class *klass_id, Eo *parent_id, Eina_Bool ref, Eina_Bool is_fallback, Efl_Substitute_Ctor_Cb substitute_ctor, void *sub_ctor_data)
1102 {
1103 return _efl_add_internal_start_do(file, line, klass_id, parent_id, ref, is_fallback, substitute_ctor, sub_ctor_data);
1104 }
1105
1106 static Eo *
_efl_add_internal_end(Eo * eo_id,Eo * finalized_id)1107 _efl_add_internal_end(Eo *eo_id, Eo *finalized_id)
1108 {
1109 EO_OBJ_POINTER_RETURN_VAL(eo_id, obj, NULL);
1110
1111 // rare so move error handling to end to save l1 instruction cache
1112 if (!obj->condtor_done) goto err_condtor;
1113 if (!finalized_id)
1114 {
1115 // XXX: Given EFL usage of objects, construction is a perfectly valid thing
1116 // to do. we shouldn't complain about it as handling a NULL obj creation is
1117 // the job of the caller. a perfect example here is ecore_con and ecore_ipc
1118 // where you create a con or ipc obj then set up type/destination/port and
1119 // the finalize of the constructor does the actual connect and thus this
1120 // fails or succeeds based on if service is there.
1121 //
1122 // until there is a better solution - don't complain here.
1123 //
1124 // ERR("Object of class '%s' - Finalizing the object failed.",
1125 // klass->desc->name);
1126 goto cleanup;
1127 }
1128
1129 obj->finalized = EINA_TRUE;
1130 _efl_unref(obj);
1131 EO_OBJ_DONE(eo_id);
1132 return (Eo *)eo_id;
1133
1134 err_condtor:
1135 {
1136 const _Efl_Class *klass = obj->klass;
1137 ERR("Object of class '%s' - Not all of the object constructors have been executed.",
1138 klass->desc->name);
1139 }
1140 cleanup:
1141 efl_parent_set((Eo *) obj->header.id, NULL);
1142 efl_unref((Eo *) obj->header.id);
1143 _efl_unref(obj);
1144 EO_OBJ_DONE(eo_id);
1145 return NULL;
1146 }
1147
1148 EAPI Eo *
_efl_add_end(Eo * eo_id,Eina_Bool is_ref,Eina_Bool is_fallback)1149 _efl_add_end(Eo *eo_id, Eina_Bool is_ref, Eina_Bool is_fallback)
1150 {
1151 if (!eo_id) return NULL;
1152 Eo *ret = efl_finalize(eo_id);
1153 ret = _efl_add_internal_end(eo_id, ret);
1154
1155 if (ret && !is_ref)
1156 {
1157 efl_unref(ret);
1158 }
1159
1160 if (is_fallback)
1161 {
1162 _efl_add_fallback_stack_pop();
1163 }
1164
1165 return ret;
1166 }
1167
1168 EAPI void
efl_reuse(const Eo * eo_id)1169 efl_reuse(const Eo *eo_id)
1170 {
1171 Eo *obj = (Eo *) eo_id;
1172 EO_OBJ_POINTER_RETURN(obj, _obj);
1173
1174 efl_object_override(obj, NULL);
1175 _efl_object_reuse(_obj);
1176
1177 #ifdef EO_DEBUG
1178 _eo_log_obj_ref_op(_obj, EO_REF_OP_REUSE);
1179 #endif
1180
1181 EO_OBJ_DONE(eo_id);
1182 }
1183
1184 void
_eo_free(_Eo_Object * obj,Eina_Bool manual_free EINA_UNUSED)1185 _eo_free(_Eo_Object *obj, Eina_Bool manual_free EINA_UNUSED)
1186 {
1187 _Efl_Class *klass = (_Efl_Class*) obj->klass;
1188
1189 _eo_log_obj_ref_op(obj, EO_REF_OP_FREE);
1190
1191 #ifdef EO_DEBUG
1192 if (manual_free)
1193 {
1194 Eo *obj_id = _eo_obj_id_get(obj);
1195 if (obj->datarefcount)
1196 {
1197 ERR("Object %p data still referenced %d time(s).", obj_id, obj->datarefcount);
1198 }
1199 while (obj->xrefs)
1200 {
1201 Eina_Inlist *nitr = obj->xrefs->next;
1202 Eo_Xref_Node *xref = EINA_INLIST_CONTAINER_GET(obj->data_xrefs, Eo_Xref_Node);
1203 ERR("Object %p is still referenced by object %p. Origin: %s:%d",
1204 obj_id, xref->ref_obj, xref->file, xref->line);
1205 eina_freeq_ptr_main_add(xref, free, sizeof(*xref));
1206 obj->xrefs = nitr;
1207 }
1208 while (obj->data_xrefs)
1209 {
1210 Eina_Inlist *nitr = obj->data_xrefs->next;
1211 Eo_Xref_Node *xref = EINA_INLIST_CONTAINER_GET(obj->data_xrefs, Eo_Xref_Node);
1212 if (obj_id == xref->ref_obj)
1213 {
1214 WRN("Object %p still has a reference to its own data (subclass: %s). Origin: %s:%d",
1215 obj_id, xref->data_klass, xref->file, xref->line);
1216 }
1217 else
1218 {
1219 ERR("Data of object %p (subclass: %s) is still referenced by object %p. Origin: %s:%d",
1220 obj_id, xref->data_klass, xref->ref_obj, xref->file, xref->line);
1221 }
1222
1223 eina_freeq_ptr_main_add(xref, free, sizeof(*xref));
1224 obj->data_xrefs = nitr;
1225 }
1226 }
1227 #endif
1228 if (obj->opt && _obj_is_override(obj))
1229 {
1230 _vtable_free(obj->opt->vtable, &obj->klass->vtable);
1231 EO_OPTIONAL_COW_SET(obj, vtable, NULL);
1232 }
1233
1234 _eo_id_release((Eo_Id) _eo_obj_id_get(obj));
1235 eina_cow_free(efl_object_optional_cow, (Eina_Cow_Data *) &obj->opt);
1236
1237 eina_spinlock_take(&klass->objects.trash_lock);
1238 if ((klass->objects.trash_count <= 8) && (EINA_LIKELY(!_eo_trash_bypass)))
1239 {
1240 eina_trash_push(&klass->objects.trash, obj);
1241 klass->objects.trash_count++;
1242 }
1243 else
1244 {
1245 eina_freeq_ptr_main_add(obj, free, klass->obj_size);
1246 }
1247 eina_spinlock_release(&klass->objects.trash_lock);
1248 }
1249 /*****************************************************************************/
1250
1251 EAPI const Efl_Class *
efl_class_get(const Eo * eo_id)1252 efl_class_get(const Eo *eo_id)
1253 {
1254 const Efl_Class *klass;
1255
1256 if (_eo_is_a_class(eo_id))
1257 {
1258 EO_CLASS_POINTER_GOTO(eo_id, _klass, err_klass);
1259 return EFL_CLASS_CLASS;
1260 }
1261
1262 EO_OBJ_POINTER_GOTO(eo_id, obj, err_obj);
1263 klass = _eo_class_id_get(obj->klass);
1264 EO_OBJ_DONE(eo_id);
1265 return klass;
1266
1267 err_klass:
1268 _EO_POINTER_ERR(eo_id, "Class (%p) is an invalid ref.", eo_id);
1269 err_obj:
1270 return NULL;
1271 }
1272
1273 EAPI const char *
efl_class_name_get(const Efl_Class * eo_id)1274 efl_class_name_get(const Efl_Class *eo_id)
1275 {
1276 const _Efl_Class *klass;
1277
1278 if (_eo_is_a_class(eo_id))
1279 {
1280 EO_CLASS_POINTER_GOTO(eo_id, _klass, err_klass);
1281 klass = _klass;
1282 }
1283 else
1284 {
1285 EO_OBJ_POINTER_GOTO(eo_id, obj, err_obj);
1286 klass = obj->klass;
1287 EO_OBJ_DONE(eo_id);
1288 }
1289 return klass->desc->name;
1290
1291 err_klass:
1292 _EO_POINTER_ERR(eo_id, "Class (%p) is an invalid ref.", eo_id);
1293 err_obj:
1294 return NULL;
1295 }
1296
1297 EAPI size_t
efl_class_memory_size_get(const Efl_Class * eo_id)1298 efl_class_memory_size_get(const Efl_Class *eo_id)
1299 {
1300 const _Efl_Class *klass;
1301
1302 if (_eo_is_a_class(eo_id))
1303 {
1304 EO_CLASS_POINTER_GOTO(eo_id, _klass, err_klass);
1305 klass = _klass;
1306 }
1307 else
1308 {
1309 EO_OBJ_POINTER_GOTO(eo_id, obj, err_obj);
1310 klass = obj->klass;
1311 EO_OBJ_DONE(eo_id);
1312 }
1313 return klass->obj_size;
1314
1315 err_klass:
1316 _EO_POINTER_ERR(eo_id, "Class (%p) is an invalid ref.", eo_id);
1317 err_obj:
1318 return 0;
1319 }
1320
1321 static Eina_Bool
_eo_class_mro_has(const _Efl_Class * klass,const _Efl_Class * find)1322 _eo_class_mro_has(const _Efl_Class *klass, const _Efl_Class *find)
1323 {
1324 const _Efl_Class **itr;
1325 for (itr = klass->mro ; *itr ; itr++)
1326 {
1327 if (*itr == find)
1328 {
1329 return EINA_TRUE;
1330 }
1331 }
1332 return EINA_FALSE;
1333 }
1334
1335 static Eina_List *
_eo_class_list_remove_duplicates(Eina_List * list)1336 _eo_class_list_remove_duplicates(Eina_List* list)
1337 {
1338 Eina_List *itr1, *itr2, *itr2n;
1339
1340 itr1 = eina_list_last(list);
1341 while (itr1)
1342 {
1343 itr2 = eina_list_prev(itr1);
1344
1345 while (itr2)
1346 {
1347 itr2n = eina_list_prev(itr2);
1348
1349 if (eina_list_data_get(itr1) == eina_list_data_get(itr2))
1350 {
1351 list = eina_list_remove_list(list, itr2);
1352 }
1353
1354 itr2 = itr2n;
1355 }
1356
1357 itr1 = eina_list_prev(itr1);
1358 }
1359
1360 return list;
1361 }
1362
1363 static Eina_List *
_eo_class_mro_add(Eina_List * mro,const _Efl_Class * klass)1364 _eo_class_mro_add(Eina_List *mro, const _Efl_Class *klass)
1365 {
1366 if (!klass)
1367 return mro;
1368
1369 mro = eina_list_append(mro, klass);
1370
1371 /* Recursively add MIXINS extensions. */
1372 {
1373 const _Efl_Class **extn_itr;
1374
1375 for (extn_itr = klass->extensions ; *extn_itr ; extn_itr++)
1376 {
1377 const _Efl_Class *extn = *extn_itr;
1378 if (extn->desc->type == EFL_CLASS_TYPE_MIXIN)
1379 mro = _eo_class_mro_add(mro, extn);
1380 }
1381 }
1382
1383 mro = _eo_class_mro_add(mro, klass->parent);
1384
1385 return mro;
1386 }
1387
1388 static Eina_List *
_eo_class_mro_init(const Efl_Class_Description * desc,const _Efl_Class * parent,Eina_List * extensions)1389 _eo_class_mro_init(const Efl_Class_Description *desc, const _Efl_Class *parent, Eina_List *extensions)
1390 {
1391 Eina_List *mro = NULL;
1392 Eina_List *extn_itr = NULL;
1393 Eina_List *extn_pos = NULL;
1394 const _Efl_Class *extn = NULL;
1395
1396 /* Add MIXINS extensions. */
1397 EINA_LIST_FOREACH(extensions, extn_itr, extn)
1398 {
1399 if (extn->desc->type != EFL_CLASS_TYPE_MIXIN)
1400 continue;
1401
1402 mro = _eo_class_mro_add(mro, extn);
1403 extn_pos = eina_list_append(extn_pos, eina_list_last(mro));
1404 }
1405
1406 /* Check if we can create a consistent mro */
1407 {
1408 Eina_List *itr = extn_pos;
1409 EINA_LIST_FOREACH(extensions, extn_itr, extn)
1410 {
1411 if (extn->desc->type != EFL_CLASS_TYPE_MIXIN)
1412 continue;
1413
1414 /* Get the first one after the extension. */
1415 Eina_List *extn_list = eina_list_next(eina_list_data_get(itr));
1416
1417 /* If we found the extension again. */
1418 if (eina_list_data_find_list(extn_list, extn))
1419 {
1420 eina_list_free(mro);
1421 eina_list_free(extn_pos);
1422 ERR("Cannot create a consistent method resolution order for class '%s' because of '%s'.", desc->name, extn->desc->name);
1423 return NULL;
1424 }
1425
1426 itr = eina_list_next(itr);
1427 }
1428 }
1429
1430 eina_list_free(extn_pos);
1431
1432 mro = _eo_class_mro_add(mro, parent);
1433 mro = _eo_class_list_remove_duplicates(mro);
1434 /* Will be replaced with the actual class pointer */
1435 mro = eina_list_prepend(mro, NULL);
1436
1437 return mro;
1438 }
1439
1440 static Eina_Bool
_eo_class_initializer(_Efl_Class * klass)1441 _eo_class_initializer(_Efl_Class *klass)
1442 {
1443 if (klass->desc->class_initializer)
1444 return klass->desc->class_initializer(_eo_class_id_get(klass));
1445
1446 return EINA_TRUE;
1447 }
1448
1449 static void
_eo_class_constructor(_Efl_Class * klass)1450 _eo_class_constructor(_Efl_Class *klass)
1451 {
1452 klass->constructed = EINA_TRUE;
1453
1454 klass->construction_thread = eina_thread_self();
1455
1456 if (klass->desc->class_constructor)
1457 klass->desc->class_constructor(_eo_class_id_get(klass));
1458 }
1459
1460 static void
eo_class_free(_Efl_Class * klass)1461 eo_class_free(_Efl_Class *klass)
1462 {
1463 void *data;
1464 Eina_Thread self = eina_thread_self();
1465
1466 if ((self != _efl_object_main_thread) &&
1467 (self != klass->construction_thread))
1468 CRI("Calling class deconstructor from thread that did not call constructor and is not main thread!\n"
1469 "This will probably crash!");
1470
1471 if (klass->constructed)
1472 {
1473 if (klass->desc->class_destructor)
1474 klass->desc->class_destructor(_eo_class_id_get(klass));
1475 _vtable_mro_free(klass);
1476 _vtable_free(&klass->vtable, NULL);
1477 }
1478
1479 EINA_TRASH_CLEAN(&klass->objects.trash, data)
1480 eina_freeq_ptr_main_add(data, free, klass->obj_size);
1481
1482 EINA_TRASH_CLEAN(&klass->iterators.trash, data)
1483 eina_freeq_ptr_main_add(data, free, 0);
1484
1485 eina_spinlock_free(&klass->objects.trash_lock);
1486 eina_spinlock_free(&klass->iterators.trash_lock);
1487
1488 eina_freeq_ptr_main_add(klass, free, 0);
1489 }
1490
1491 static inline void
_eo_classes_release(void)1492 _eo_classes_release(void)
1493 {
1494 #ifdef HAVE_MMAP
1495 # ifdef HAVE_VALGRIND
1496 if (RUNNING_ON_VALGRIND) free(_eo_classes);
1497 else
1498 # endif
1499 {
1500 size_t size;
1501
1502 size = _eo_classes_alloc * sizeof(_Efl_Class *);
1503 if (_eo_classes) munmap(_eo_classes, size);
1504 }
1505 #else
1506 free(_eo_classes);
1507 #endif
1508 _eo_classes = NULL;
1509 _eo_classes_last_id = 0;
1510 _eo_classes_alloc = 0;
1511 }
1512
1513 static inline void
_eo_classes_expand(void)1514 _eo_classes_expand(void)
1515 {
1516 unsigned char *ptr;
1517 size_t newsize, psize;
1518
1519 _eo_classes_last_id++;
1520 if (_eo_classes_last_id <= _eo_classes_alloc) return;
1521 psize = _eo_classes_alloc * sizeof(_Efl_Class *);
1522 #ifdef HAVE_MMAP
1523 # ifdef HAVE_VALGRIND
1524 if (RUNNING_ON_VALGRIND)
1525 {
1526 _eo_classes_alloc += 128;
1527 newsize = _eo_classes_alloc * sizeof(_Efl_Class *);
1528 ptr = realloc(_eo_classes, newsize);
1529 if (!ptr)
1530 {
1531 ERR("realloc of eo class table region faile!!");
1532 abort();
1533 }
1534 }
1535 else
1536 # endif
1537 {
1538 _eo_classes_alloc += (MEM_PAGE_SIZE / sizeof(_Efl_Class *));
1539 newsize = _eo_classes_alloc * sizeof(_Efl_Class *);
1540 ptr = mmap(NULL, newsize, PROT_READ | PROT_WRITE,
1541 MAP_PRIVATE | MAP_ANON, -1, 0);
1542 if (ptr == MAP_FAILED)
1543 {
1544 ERR("mmap of eo class table region failed!");
1545 abort();
1546 }
1547 if (psize > 0) memcpy(ptr, _eo_classes, psize);
1548 if (_eo_classes) munmap(_eo_classes, psize);
1549 }
1550 #else
1551 _eo_classes_alloc += 128;
1552 newsize = _eo_classes_alloc * sizeof(_Efl_Class *);
1553 ptr = realloc(_eo_classes, newsize);
1554 if (!ptr)
1555 {
1556 ERR("realloc of eo class table region faile!!");
1557 abort();
1558 }
1559 #endif
1560 memset(ptr + psize, 0, newsize - psize);
1561 _eo_classes = (_Efl_Class **)ptr;
1562 }
1563
1564 EAPI const Efl_Class *
efl_class_new(const Efl_Class_Description * desc,const Efl_Class * parent_id,...)1565 efl_class_new(const Efl_Class_Description *desc, const Efl_Class *parent_id, ...)
1566 {
1567 _Efl_Class *klass;
1568 va_list p_list;
1569 size_t extn_sz, mro_sz, mixins_sz;
1570 Eina_List *extn_list, *mro, *mixins;
1571 _Efl_Class *parent = NULL;
1572
1573 EINA_SAFETY_ON_NULL_RETURN_VAL(desc, NULL);
1574 EINA_SAFETY_ON_NULL_RETURN_VAL(desc->name, NULL);
1575
1576 if (parent_id)
1577 {
1578 parent = _eo_class_pointer_get(parent_id);
1579 if (!parent)
1580 return NULL;
1581 }
1582
1583 /* Check restrictions on Interface types. */
1584 if (desc->type == EFL_CLASS_TYPE_INTERFACE)
1585 {
1586 EINA_SAFETY_ON_FALSE_RETURN_VAL(!desc->data_size, NULL);
1587 }
1588
1589 /* Check parent */
1590 if (parent)
1591 {
1592 /* Verify the inheritance is allowed. */
1593 switch (desc->type)
1594 {
1595 case EFL_CLASS_TYPE_REGULAR:
1596 case EFL_CLASS_TYPE_REGULAR_NO_INSTANT:
1597 if ((parent->desc->type != EFL_CLASS_TYPE_REGULAR) &&
1598 (parent->desc->type != EFL_CLASS_TYPE_REGULAR_NO_INSTANT))
1599 {
1600 ERR("Regular classes ('%s') aren't allowed to inherit from non-regular classes ('%s').",
1601 desc->name, parent->desc->name);
1602 return NULL;
1603 }
1604 break;
1605 case EFL_CLASS_TYPE_INTERFACE:
1606 case EFL_CLASS_TYPE_MIXIN:
1607 if ((parent->desc->type != EFL_CLASS_TYPE_INTERFACE) &&
1608 (parent->desc->type != EFL_CLASS_TYPE_MIXIN))
1609 {
1610 ERR("Non-regular classes ('%s') aren't allowed to inherit from regular classes ('%s').",
1611 desc->name, parent->desc->name);
1612 return NULL;
1613 }
1614 break;
1615 default:
1616 ERR("type cannot be INVALID");
1617 return NULL;
1618 }
1619 }
1620
1621 /* Build class extensions list */
1622 {
1623 DBG("Started building extensions list for class '%s'", desc->name);
1624 extn_list = NULL;
1625 const _Efl_Class *extn = NULL;
1626 const Eo_Id *extn_id = NULL;
1627
1628 va_start(p_list, parent_id);
1629
1630 extn_id = va_arg(p_list, Eo_Id *);
1631 while (extn_id)
1632 {
1633 extn = _eo_class_pointer_get((Efl_Class *)extn_id);
1634 if (EINA_LIKELY(extn != NULL))
1635 {
1636 switch (extn->desc->type)
1637 {
1638 case EFL_CLASS_TYPE_REGULAR_NO_INSTANT:
1639 case EFL_CLASS_TYPE_REGULAR:
1640 case EFL_CLASS_TYPE_INTERFACE:
1641 case EFL_CLASS_TYPE_MIXIN:
1642 extn_list = eina_list_append(extn_list, extn);
1643 break;
1644 default:
1645 ERR("type cannot be INVALID");
1646 va_end(p_list);
1647 return NULL;
1648 }
1649 }
1650 extn_id = va_arg(p_list, Eo_Id *);
1651 }
1652
1653 va_end(p_list);
1654
1655 extn_list = _eo_class_list_remove_duplicates(extn_list);
1656
1657 extn_sz = sizeof(_Efl_Class *) * (eina_list_count(extn_list) + 1);
1658
1659 DBG("Finished building extensions list for class '%s'", desc->name);
1660 }
1661
1662 /* Prepare mro list */
1663 {
1664 DBG("Started building MRO list for class '%s'", desc->name);
1665
1666 mro = _eo_class_mro_init(desc, parent, extn_list);
1667 if (!mro)
1668 {
1669 eina_list_free(extn_list);
1670 return NULL;
1671 }
1672
1673 mro_sz = sizeof(_Efl_Class *) * (eina_list_count(mro) + 1);
1674
1675 DBG("Finished building MRO list for class '%s'", desc->name);
1676 }
1677
1678 /* Prepare mixins list */
1679 {
1680 Eina_List *itr;
1681 const _Efl_Class *kls_itr;
1682
1683 DBG("Started building Mixins list for class '%s'", desc->name);
1684
1685 mixins = NULL;
1686 EINA_LIST_FOREACH(mro, itr, kls_itr)
1687 {
1688 if ((kls_itr) && (kls_itr->desc->type == EFL_CLASS_TYPE_MIXIN) &&
1689 (kls_itr->desc->data_size > 0))
1690 mixins = eina_list_append(mixins, kls_itr);
1691 }
1692
1693 mixins_sz = sizeof(Eo_Extension_Data_Offset) * (eina_list_count(mixins) + 1);
1694 if ((desc->type == EFL_CLASS_TYPE_MIXIN) && (desc->data_size > 0))
1695 mixins_sz += sizeof(Eo_Extension_Data_Offset);
1696
1697 DBG("Finished building Mixins list for class '%s'", desc->name);
1698 }
1699
1700 klass = calloc(1, _eo_class_sz + extn_sz + mro_sz + mixins_sz);
1701 eina_spinlock_new(&klass->objects.trash_lock);
1702 eina_spinlock_new(&klass->iterators.trash_lock);
1703 klass->parent = parent;
1704 klass->desc = desc;
1705 klass->extensions = (const _Efl_Class **) ((char *) klass + _eo_class_sz);
1706 klass->mro = (const _Efl_Class **) ((char *) klass->extensions + extn_sz);
1707 klass->extn_data_off = (Eo_Extension_Data_Offset *) ((char *) klass->mro + mro_sz);
1708
1709 if (klass->parent)
1710 {
1711 /* FIXME: Make sure this alignment is enough. */
1712 klass->data_offset = klass->parent->data_offset +
1713 EO_ALIGN_SIZE(klass->parent->desc->data_size);
1714 }
1715 else
1716 {
1717 /* Data starts after the object size. */
1718 klass->data_offset = _eo_sz;
1719 }
1720
1721 mro = eina_list_remove(mro, NULL);
1722 mro = eina_list_prepend(mro, klass);
1723 if ((desc->type == EFL_CLASS_TYPE_MIXIN) && (desc->data_size > 0))
1724 {
1725 mixins = eina_list_prepend(mixins, klass);
1726 }
1727
1728 /* Copy the extensions and free the list */
1729 {
1730 const _Efl_Class *extn = NULL;
1731 const _Efl_Class **extn_itr = klass->extensions;
1732 EINA_LIST_FREE(extn_list, extn)
1733 {
1734 *(extn_itr++) = extn;
1735
1736 DBG("Added '%s' extension", extn->desc->name);
1737 }
1738 *(extn_itr) = NULL;
1739 }
1740
1741 /* Copy the mro and free the list. */
1742 {
1743 const _Efl_Class *kls_itr = NULL;
1744 const _Efl_Class **mro_itr = klass->mro;
1745 EINA_LIST_FREE(mro, kls_itr)
1746 {
1747 *(mro_itr++) = kls_itr;
1748
1749 DBG("Added '%s' to MRO", kls_itr->desc->name);
1750 }
1751 *(mro_itr) = NULL;
1752 }
1753
1754 size_t extn_data_off = klass->data_offset;
1755 if (klass->desc->type != EFL_CLASS_TYPE_MIXIN)
1756 {
1757 extn_data_off += EO_ALIGN_SIZE(klass->desc->data_size);
1758 }
1759
1760 /* Feed the mixins data offsets and free the mixins list. */
1761 {
1762 const _Efl_Class *kls_itr = NULL;
1763 Eo_Extension_Data_Offset *extn_data_itr = klass->extn_data_off;
1764 EINA_LIST_FREE(mixins, kls_itr)
1765 {
1766 extn_data_itr->klass = kls_itr;
1767 extn_data_itr->offset = extn_data_off;
1768
1769 extn_data_off += EO_ALIGN_SIZE(extn_data_itr->klass->desc->data_size);
1770 extn_data_itr++;
1771
1772 DBG("Added '%s' to Data Offset info", kls_itr->desc->name);
1773 }
1774 extn_data_itr->klass = 0;
1775 extn_data_itr->offset = 0;
1776 }
1777
1778 klass->obj_size = extn_data_off;
1779
1780 {
1781 Eo_Id new_id;
1782
1783 eina_lock_take(&_efl_class_creation_lock);
1784 new_id = (_eo_classes_last_id + 1) | MASK_CLASS_TAG;
1785 _eo_classes_expand();
1786 _eo_classes[_UNMASK_ID(new_id) - 1] = klass;
1787 eina_lock_release(&_efl_class_creation_lock);
1788
1789 klass->header.id = new_id;
1790 }
1791
1792 if (!_eo_class_initializer(klass))
1793 {
1794 return NULL;
1795 }
1796
1797 /* If functions haven't been set, invoke it with an empty ops structure. */
1798 if (!klass->functions_set)
1799 {
1800 efl_class_functions_set(_eo_class_id_get(klass), NULL, NULL);
1801 }
1802
1803 _eo_class_constructor(klass);
1804
1805 DBG("Finished building class '%s'", klass->desc->name);
1806
1807 return _eo_class_id_get(klass);
1808 }
1809
1810 EAPI Eina_Bool
efl_object_override(Eo * eo_id,const Efl_Object_Ops * ops)1811 efl_object_override(Eo *eo_id, const Efl_Object_Ops *ops)
1812 {
1813 EO_OBJ_POINTER_RETURN_VAL(eo_id, obj, EINA_FALSE);
1814 EO_CLASS_POINTER_GOTO(EFL_OBJECT_OVERRIDE_CLASS, klass, err);
1815
1816 if (ops)
1817 {
1818 Eo_Vtable *vtable = obj->opt->vtable;
1819 //copy all the vtable nodes that we are going to change later on
1820 Eina_Bool *hitmap;
1821
1822 if (!vtable)
1823 {
1824 vtable = calloc(1, sizeof(*vtable));
1825 _vtable_init_size(vtable, obj->klass->vtable.size);
1826 _vtable_take_over(vtable, &obj->klass->vtable);
1827 }
1828
1829 hitmap = alloca(vtable->size * sizeof(Eina_Bool));
1830 memset(hitmap, 0, vtable->size);
1831
1832 if (!_eo_class_funcs_set(vtable, ops, obj->klass, klass, EINA_TRUE, obj->klass->class_id, hitmap))
1833 {
1834 ERR("Failed to override functions for %s@%p. All previous "
1835 "overrides have been reset.", obj->klass->desc->name, eo_id);
1836 if (obj->opt->vtable == vtable)
1837 {
1838 EO_OPTIONAL_COW_SET(obj, vtable, NULL);
1839 }
1840 else
1841 {
1842 _vtable_free(vtable, &obj->klass->vtable);
1843 free(vtable);
1844 }
1845
1846 goto err;
1847 }
1848 EO_OPTIONAL_COW_SET(obj, vtable, vtable);
1849 }
1850 else
1851 {
1852 if (obj->opt->vtable)
1853 {
1854 _vtable_free(obj->opt->vtable, &obj->klass->vtable);
1855 EO_OPTIONAL_COW_SET(obj, vtable, NULL);
1856 }
1857 }
1858
1859 EO_OBJ_DONE(eo_id);
1860 return EINA_TRUE;
1861
1862 err:
1863 EO_OBJ_DONE(eo_id);
1864 return EINA_FALSE;
1865 }
1866
1867 EAPI Eina_Bool
efl_isa(const Eo * eo_id,const Efl_Class * klass_id)1868 efl_isa(const Eo *eo_id, const Efl_Class *klass_id)
1869 {
1870 Efl_Id_Domain domain;
1871 Eo_Id_Data *data;
1872 Eo_Id_Table_Data *tdata;
1873 Eina_Bool isa = EINA_FALSE;
1874
1875 if (EINA_UNLIKELY(!eo_id)) return EINA_FALSE;
1876
1877 // Everything can add a override to an existing class, which pretty much means, everything is a efl override
1878 // This is required in order to support our debug-profile for the users of efl_override
1879 if (EINA_UNLIKELY(klass_id == EFL_OBJECT_OVERRIDE_CLASS)) return EINA_TRUE;
1880
1881 // Case where we are looking if eo_id is a class that contain klass_id
1882 if (EINA_UNLIKELY(_eo_is_a_class(eo_id)))
1883 {
1884
1885 EO_CLASS_POINTER_GOTO(klass_id, klass, err_class);
1886 EO_CLASS_POINTER_GOTO(eo_id, lookinto, err_class0);
1887
1888 if (EINA_UNLIKELY(lookinto->vtable.size <= klass->class_id))
1889 return EINA_FALSE;
1890
1891 return !!lookinto->vtable.chain[klass->class_id].funcs;
1892 }
1893
1894 domain = ((Eo_Id)eo_id >> SHIFT_DOMAIN) & MASK_DOMAIN;
1895 data = _eo_table_data_get();
1896 tdata = _eo_table_data_table_get(data, domain);
1897 if (EINA_UNLIKELY(!tdata)) goto err;
1898
1899 if (EINA_LIKELY(domain != EFL_ID_DOMAIN_SHARED))
1900 {
1901 if ((tdata->cache.isa_id == eo_id) &&
1902 (tdata->cache.klass == klass_id))
1903 {
1904 isa = tdata->cache.isa;
1905 return isa;
1906 }
1907
1908 EO_OBJ_POINTER_GOTO(eo_id, obj, err_obj);
1909 EO_CLASS_POINTER_GOTO(klass_id, klass, err_class);
1910
1911 const Eo_Vtable vtable = obj->klass->vtable;
1912 if (EINA_UNLIKELY(vtable.size <= klass->class_id))
1913 return EINA_FALSE;
1914
1915 isa = !!vtable.chain[klass->class_id].funcs;
1916
1917 // Caching the result as we do a lot of serial efl_isa due to evas_object_image using it.
1918 tdata->cache.isa_id = eo_id;
1919 tdata->cache.klass = klass_id;
1920 tdata->cache.isa = isa;
1921 }
1922 else
1923 {
1924 eina_lock_take(&(_eo_table_data_shared_data->obj_lock));
1925
1926 if ((tdata->cache.isa_id == eo_id) &&
1927 (tdata->cache.klass == klass_id))
1928 {
1929 isa = tdata->cache.isa;
1930 // since this is the cache we hope this gets a lot of hits and
1931 // thus lets assume the hit is the mot important thing thus
1932 // put the lock release and return here inline in the l1
1933 // instruction cache hopefully already fetched
1934 eina_lock_release(&(_eo_table_data_shared_data->obj_lock));
1935 return isa;
1936 }
1937
1938 EO_OBJ_POINTER_GOTO(eo_id, obj, err_shared_obj);
1939 EO_CLASS_POINTER_GOTO(klass_id, klass, err_shared_class);
1940 if (EINA_UNLIKELY(obj->klass->vtable.size <= klass->class_id))
1941 goto err_vtable;
1942
1943 isa = !!obj->klass->vtable.chain[klass->class_id].funcs;
1944
1945 // Caching the result as we do a lot of serial efl_isa due to evas_object_image using it.
1946 tdata->cache.isa_id = eo_id;
1947 tdata->cache.klass = klass_id;
1948 tdata->cache.isa = isa;
1949 err_vtable:
1950 EO_OBJ_DONE(eo_id);
1951 eina_lock_release(&(_eo_table_data_shared_data->obj_lock));
1952 }
1953 return isa;
1954
1955 err_shared_class: EINA_COLD
1956 _EO_POINTER_ERR(klass_id, "Class (%p) is an invalid ref.", klass_id);
1957 EO_OBJ_DONE(eo_id);
1958 err_shared_obj: EINA_COLD
1959 eina_lock_release(&(_eo_table_data_shared_data->obj_lock));
1960 return EINA_FALSE;
1961
1962 err_class0:
1963 _EO_POINTER_ERR(eo_id, "Class (%p) is an invalid ref.", eo_id);
1964 return EINA_FALSE;
1965
1966 err_class: EINA_COLD
1967 _EO_POINTER_ERR(klass_id, "Class (%p) is an invalid ref.", klass_id);
1968 err_obj:
1969 return EINA_FALSE;
1970
1971 err: EINA_COLD
1972 ERR("Object %p is not a valid object in this context: object domain: %d, "
1973 "current domain: %d, local domain: %d, available domains: [%s %s %s %s]."
1974 " Are you trying to access this object from another thread?",
1975 eo_id, (int)domain,
1976 (int)data->domain_stack[data->stack_top], (int)data->local_domain,
1977 (data->tables[0]) ? "0" : " ", (data->tables[1]) ? "1" : " ",
1978 (data->tables[2]) ? "2" : " ", (data->tables[3]) ? "3" : " ");
1979 return EINA_FALSE;
1980 }
1981
1982 EAPI Eo *
efl_xref_internal(const char * file,int line,Eo * obj_id,const Eo * ref_obj_id)1983 efl_xref_internal(const char *file, int line, Eo *obj_id, const Eo *ref_obj_id)
1984 {
1985 efl_ref(obj_id);
1986
1987 #ifdef EO_DEBUG
1988 const char *func_name = __func__;
1989 EO_OBJ_POINTER_RETURN_VAL_PROXY(obj_id, obj, obj_id);
1990
1991 Eo_Xref_Node *xref = calloc(1, sizeof(*xref));
1992 xref->ref_obj = ref_obj_id;
1993 xref->file = file;
1994 xref->line = line;
1995
1996 obj->xrefs = eina_inlist_prepend(obj->xrefs, EINA_INLIST_GET(xref));
1997 EO_OBJ_DONE(obj_id);
1998 #else
1999 (void) ref_obj_id;
2000 (void) file;
2001 (void) line;
2002 #endif
2003
2004 return obj_id;
2005 }
2006
2007 EAPI void
efl_xunref(Eo * obj_id,const Eo * ref_obj_id)2008 efl_xunref(Eo *obj_id, const Eo *ref_obj_id)
2009 {
2010 EO_OBJ_POINTER_RETURN(obj_id, obj);
2011 #ifdef EO_DEBUG
2012 Eo_Xref_Node *xref = NULL;
2013 EINA_INLIST_FOREACH(obj->xrefs, xref)
2014 {
2015 if (xref->ref_obj == ref_obj_id)
2016 break;
2017 }
2018
2019 if (xref)
2020 {
2021 obj->xrefs = eina_inlist_remove(obj->xrefs, EINA_INLIST_GET(xref));
2022 eina_freeq_ptr_main_add(xref, free, sizeof(*xref));
2023 }
2024 else
2025 {
2026 ERR("ref_obj (%p) does not reference obj (%p). Aborting unref.", ref_obj_id, obj_id);
2027 EO_OBJ_DONE(obj_id);
2028 return;
2029 }
2030 EO_OBJ_DONE(obj_id);
2031 #else
2032 (void) ref_obj_id;
2033 #endif
2034 efl_unref(obj_id);
2035 }
2036
2037 EAPI Eo *
efl_ref(const Eo * obj_id)2038 efl_ref(const Eo *obj_id)
2039 {
2040 EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, (Eo *)obj_id);
2041
2042 ++(obj->user_refcount);
2043 if (EINA_UNLIKELY(obj->user_refcount == 1))
2044 _efl_ref(obj);
2045 else if (EINA_UNLIKELY(obj->ownership_track && obj->user_refcount == 2))
2046 efl_event_callback_call((Eo *) obj_id, EFL_EVENT_OWNERSHIP_SHARED, NULL);
2047
2048 #ifdef EO_DEBUG
2049 _eo_log_obj_ref_op(obj, EO_REF_OP_REF);
2050 #endif
2051 EO_OBJ_DONE(obj_id);
2052 return (Eo *)obj_id;
2053 }
2054
2055 EAPI void
efl_unref(const Eo * obj_id)2056 efl_unref(const Eo *obj_id)
2057 {
2058 EO_OBJ_POINTER_RETURN(obj_id, obj);
2059
2060 if (EINA_UNLIKELY((!obj->unref_compensate && obj->user_refcount == 1 && obj->parent) ||
2061 (obj->unref_compensate && obj->user_refcount == 2 && obj->parent)))
2062 {
2063 if (!obj->allow_parent_unref)
2064 CRI("Calling efl_unref instead of efl_del or efl_parent_set(NULL). Temporary fallback in place triggered.");
2065 EO_OBJ_DONE(obj_id);
2066 efl_del(obj_id);
2067 return ;
2068 }
2069
2070 _efl_ref(obj);
2071
2072 if (EINA_UNLIKELY((obj->noref_event) && (!obj->unref_compensate) &&
2073 ((obj->user_refcount == 1 && !obj->parent) ||
2074 (obj->user_refcount == 2 && obj->parent))))
2075 {
2076 // We need to report efl_ref_count correctly during EFL_EVENT_NOREF, so fake it
2077 // by adjusting efl_ref_count while inside efl_unref (This should avoid
2078 // infinite loop)
2079 obj->unref_compensate = EINA_TRUE;
2080
2081 // The noref event should happen before any object in the
2082 // tree get affected by the change in refcount.
2083 efl_event_callback_call((Eo *) obj_id, EFL_EVENT_NOREF, NULL);
2084
2085 obj->unref_compensate = EINA_FALSE;
2086 }
2087
2088 --(obj->user_refcount);
2089
2090 #ifdef EO_DEBUG
2091 _eo_log_obj_ref_op(obj, EO_REF_OP_UNREF);
2092 #endif
2093 if (EINA_UNLIKELY((obj->user_refcount <= 0)))
2094 {
2095 if (obj->user_refcount < 0)
2096 {
2097 ERR("Obj:%s@%p. User refcount (%d) < 0. Too many unrefs.",
2098 obj->klass->desc->name, obj_id, obj->user_refcount);
2099 _eo_log_obj_report((Eo_Id)obj_id, EINA_LOG_LEVEL_ERR, __func__, __FILE__, __LINE__);
2100 EO_OBJ_DONE(obj_id);
2101 _efl_unref(obj);
2102 return;
2103 }
2104 _efl_unref(obj);
2105 }
2106 else if (EINA_UNLIKELY(obj->ownership_track && obj->user_refcount == 1))
2107 {
2108 efl_event_callback_call((Eo *) obj_id, EFL_EVENT_OWNERSHIP_UNIQUE, NULL);
2109 }
2110
2111 _apply_auto_unref(obj, obj_id);
2112
2113 _efl_unref(obj);
2114 EO_OBJ_DONE(obj_id);
2115 }
2116
2117 EAPI int
efl_ref_count(const Eo * obj_id)2118 efl_ref_count(const Eo *obj_id)
2119 {
2120 EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, 0);
2121 int ref;
2122 ref = obj->user_refcount - (obj->unref_compensate ? 1 : 0);
2123 EO_OBJ_DONE(obj_id);
2124 return ref;
2125 }
2126
2127 EAPI int
___efl_ref2_count(const Eo * obj_id)2128 ___efl_ref2_count(const Eo *obj_id)
2129 {
2130 EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, 0);
2131 int ref;
2132 ref = obj->refcount;
2133 EO_OBJ_DONE(obj_id);
2134 return ref;
2135 }
2136
2137 EAPI void
___efl_ref2_reset(const Eo * obj_id)2138 ___efl_ref2_reset(const Eo *obj_id)
2139 {
2140 EO_OBJ_POINTER_RETURN(obj_id, obj);
2141 obj->refcount = 0;
2142 EO_OBJ_DONE(obj_id);
2143 }
2144
2145
2146 EAPI void
efl_del_intercept_set(Eo * obj_id,Efl_Del_Intercept del_intercept_func)2147 efl_del_intercept_set(Eo *obj_id, Efl_Del_Intercept del_intercept_func)
2148 {
2149 EO_OBJ_POINTER_RETURN(obj_id, obj);
2150 EO_OPTIONAL_COW_SET(obj, del_intercept, del_intercept_func);
2151 EO_OBJ_DONE(obj_id);
2152 }
2153
2154 EAPI Efl_Del_Intercept
efl_del_intercept_get(const Eo * obj_id)2155 efl_del_intercept_get(const Eo *obj_id)
2156 {
2157 Efl_Del_Intercept func;
2158
2159 EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, NULL);
2160 func = obj->opt->del_intercept;
2161 EO_OBJ_DONE(obj_id);
2162 return func;
2163 }
2164
2165 void
_eo_condtor_done(Eo * obj_id)2166 _eo_condtor_done(Eo *obj_id)
2167 {
2168 EO_OBJ_POINTER_RETURN(obj_id, obj);
2169 if (obj->condtor_done)
2170 {
2171 ERR("Object %p is already constructed at this point.", obj);
2172 EO_OBJ_DONE(obj_id);
2173 return;
2174 }
2175 obj->condtor_done = EINA_TRUE;
2176 EO_OBJ_DONE(obj_id);
2177 }
2178
2179 static inline void *
_efl_data_scope_safe_get(const _Eo_Object * obj,const _Efl_Class * klass)2180 _efl_data_scope_safe_get(const _Eo_Object *obj, const _Efl_Class *klass)
2181 {
2182 if (EINA_LIKELY(klass->desc->data_size > 0))
2183 {
2184 return _efl_data_scope_get(obj, klass);
2185 }
2186
2187 return NULL;
2188 }
2189
2190 static inline void *
_efl_data_scope_get(const _Eo_Object * obj,const _Efl_Class * klass)2191 _efl_data_scope_get(const _Eo_Object *obj, const _Efl_Class *klass)
2192 {
2193 if (EINA_LIKELY(klass->desc->type != EFL_CLASS_TYPE_MIXIN))
2194 return ((char *) obj) + klass->data_offset;
2195
2196 if (EINA_UNLIKELY(klass->desc->data_size == 0))
2197 {
2198 return NULL;
2199 }
2200 else
2201 {
2202 Eo_Extension_Data_Offset *doff_itr = obj->klass->extn_data_off;
2203
2204 if (!doff_itr)
2205 return NULL;
2206
2207 while (doff_itr->klass)
2208 {
2209 if (doff_itr->klass == klass)
2210 return ((char *) obj) + doff_itr->offset;
2211 doff_itr++;
2212 }
2213 }
2214
2215 return NULL;
2216 }
2217
2218 static inline void *
_efl_data_xref_internal(const char * file,int line,_Eo_Object * obj,const _Efl_Class * klass,const _Eo_Object * ref_obj)2219 _efl_data_xref_internal(const char *file, int line, _Eo_Object *obj, const _Efl_Class *klass, const _Eo_Object *ref_obj)
2220 {
2221 void *data = NULL;
2222 if (klass != NULL)
2223 {
2224 data = _efl_data_scope_safe_get(obj, klass);
2225 if (data == NULL) return NULL;
2226 }
2227 #ifdef EO_DEBUG
2228 (obj->datarefcount)++;
2229 Eo_Xref_Node *xref = calloc(1, sizeof(*xref));
2230 xref->ref_obj = _eo_obj_id_get(ref_obj);
2231 xref->data_klass = klass ? klass->desc->name : NULL;
2232 xref->file = file;
2233 xref->line = line;
2234
2235 obj->data_xrefs = eina_inlist_prepend(obj->data_xrefs, EINA_INLIST_GET(xref));
2236 #else
2237 (void) ref_obj;
2238 (void) file;
2239 (void) line;
2240 #endif
2241 return data;
2242 }
2243
2244 static inline void
_efl_data_xunref_internal(_Eo_Object * obj EINA_UNUSED,void * data EINA_UNUSED,const _Eo_Object * ref_obj EINA_UNUSED)2245 _efl_data_xunref_internal(_Eo_Object *obj EINA_UNUSED, void *data EINA_UNUSED, const _Eo_Object *ref_obj EINA_UNUSED)
2246 {
2247 #ifdef EO_DEBUG
2248 const _Efl_Class *klass = obj->klass;
2249 Eo_Xref_Node *xref = NULL;
2250 Eina_Bool in_range = (((char *)data >= (((char *) obj) + _eo_sz)) &&
2251 ((char *)data < (((char *) obj) + klass->obj_size)));
2252 if (!in_range)
2253 {
2254 ERR("Data %p is not in the data range of the object %p (%s).",
2255 data, _eo_obj_id_get(obj), obj->klass->desc->name);
2256 }
2257 if (obj->datarefcount == 0)
2258 {
2259 ERR("Data for object %p (%s) is already not referenced.",
2260 _eo_obj_id_get(obj), obj->klass->desc->name);
2261 }
2262 else
2263 {
2264 (obj->datarefcount)--;
2265 }
2266 EINA_INLIST_FOREACH(obj->data_xrefs, xref)
2267 {
2268 if (xref->ref_obj == _eo_obj_id_get(ref_obj))
2269 break;
2270 }
2271 if (xref)
2272 {
2273 obj->data_xrefs = eina_inlist_remove(obj->data_xrefs, EINA_INLIST_GET(xref));
2274 eina_freeq_ptr_main_add(xref, free, sizeof(*xref));
2275 }
2276 else
2277 {
2278 ERR("ref_obj %p (%s) does not reference data %p of obj %p (%s).",
2279 _eo_obj_id_get(ref_obj), ref_obj->klass->desc->name, data,
2280 _eo_obj_id_get(obj), obj->klass->desc->name);
2281 }
2282 #endif
2283 }
2284
2285 EAPI void *
efl_data_scope_get(const Eo * obj_id,const Efl_Class * klass_id)2286 efl_data_scope_get(const Eo *obj_id, const Efl_Class *klass_id)
2287 {
2288 void *ret = NULL;
2289 EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, NULL);
2290 EO_CLASS_POINTER_GOTO(klass_id, klass, err_klass);
2291
2292 #ifndef EO_DEBUG
2293 ret = _efl_data_scope_safe_get(obj, klass);
2294 #else
2295 if (_eo_class_mro_has(obj->klass, klass))
2296 {
2297 ret = _efl_data_scope_safe_get(obj, klass);
2298 if (!ret && (klass->desc->data_size == 0))
2299 ERR("Tried getting data of class '%s', but it has none.", klass->desc->name);
2300 }
2301 else
2302 {
2303 ERR("Tried getting data of class '%s' from object of class '%s', but the former is not a direct inheritance of the latter.",
2304 klass->desc->name, obj->klass->desc->name);
2305 }
2306 #endif
2307
2308 err_klass:
2309 EO_OBJ_DONE(obj_id);
2310 return ret;
2311 }
2312
2313 EAPI void *
efl_data_scope_safe_get(const Eo * obj_id,const Efl_Class * klass_id)2314 efl_data_scope_safe_get(const Eo *obj_id, const Efl_Class *klass_id)
2315 {
2316 void *ret = NULL;
2317
2318 if (!obj_id) return NULL;
2319 EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, NULL);
2320 EO_CLASS_POINTER_GOTO(klass_id, klass, err_klass);
2321 if (obj->destructed) goto err_klass;
2322
2323 if (_eo_class_mro_has(obj->klass, klass))
2324 {
2325 ret = _efl_data_scope_safe_get(obj, klass);
2326
2327 #ifdef EO_DEBUG
2328 if (!ret && (klass->desc->data_size == 0))
2329 ERR("Tried getting data of class '%s', but it has none.", klass->desc->name);
2330 #endif
2331 }
2332
2333 err_klass:
2334 EO_OBJ_DONE(obj_id);
2335 return ret;
2336 }
2337
2338 EAPI void *
efl_data_xref_internal(const char * file,int line,const Eo * obj_id,const Efl_Class * klass_id,const Eo * ref_obj_id)2339 efl_data_xref_internal(const char *file, int line, const Eo *obj_id, const Efl_Class *klass_id, const Eo *ref_obj_id)
2340 {
2341 void *ret = NULL;
2342 _Efl_Class *klass = NULL;
2343 const char *func_name = __func__;
2344 EO_OBJ_POINTER_RETURN_VAL_PROXY(obj_id, obj, NULL);
2345 EO_OBJ_POINTER_PROXY(ref_obj_id, ref_obj);
2346 if (ref_obj)
2347 {
2348 if (klass_id)
2349 {
2350 EO_CLASS_POINTER_GOTO_PROXY(klass_id, klass2, err_klass);
2351 klass = klass2;
2352 #ifdef EO_DEBUG
2353 // rare to use goto to keep instruction cache cleaner
2354 if (!_eo_class_mro_has(obj->klass, klass)) goto err_mro;
2355 #endif
2356 }
2357
2358 ret = _efl_data_xref_internal(file, line, obj, klass, ref_obj);
2359 #ifdef EO_DEBUG
2360 // rare to use goto to keep instruction cache cleaner
2361 if (klass && !ret && (klass->desc->data_size == 0)) goto err_ret;
2362 #endif
2363 err_klass:
2364 EO_OBJ_DONE(ref_obj_id);
2365 }
2366 EO_OBJ_DONE(obj_id);
2367 return ret;
2368 #ifdef EO_DEBUG
2369 err_ret:
2370 ERR("Tried getting data of class '%s', but it has none.", klass->desc->name);
2371 goto err;
2372 err_mro:
2373 ERR("Tried getting data of class '%s' from object of class '%s', but the former is not a direct inheritance of the latter.", klass->desc->name, obj->klass->desc->name);
2374 err:
2375 EO_OBJ_DONE(obj_id);
2376 EO_OBJ_DONE(ref_obj_id);
2377 return NULL;
2378 #endif
2379 }
2380
2381 EAPI void
efl_data_xunref_internal(const Eo * obj_id,void * data,const Eo * ref_obj_id)2382 efl_data_xunref_internal(const Eo *obj_id, void *data, const Eo *ref_obj_id)
2383 {
2384 EO_OBJ_POINTER_RETURN(obj_id, obj);
2385 EO_OBJ_POINTER(ref_obj_id, ref_obj);
2386 if (ref_obj)
2387 {
2388 _efl_data_xunref_internal(obj, data, ref_obj);
2389 EO_OBJ_DONE(ref_obj_id);
2390 }
2391 EO_OBJ_DONE(obj_id);
2392 }
2393
2394 static void
_eo_table_del_cb(void * in)2395 _eo_table_del_cb(void *in)
2396 {
2397 Eo_Id_Data *data = in;
2398 _eo_free_ids_tables(data);
2399 }
2400
2401 /* FIXME: Support other domains and tables, at the moment only the main
2402 * domain and table.
2403 * This is used by the gdb debug helper script */
2404 Eo_Id_Data *_eo_gdb_main_domain = NULL;
2405
2406 EAPI Eina_Bool
efl_object_init(void)2407 efl_object_init(void)
2408 {
2409 const char *log_dom = "eo";
2410 if (_efl_object_init_count++ > 0)
2411 return EINA_TRUE;
2412
2413 eina_init();
2414
2415 #if HAVE_VALGRIND
2416 _eo_trash_bypass = RUNNING_ON_VALGRIND;
2417 #endif
2418
2419 _efl_object_main_thread = eina_thread_self();
2420
2421 _eo_sz = EO_ALIGN_SIZE(sizeof(_Eo_Object));
2422 _eo_class_sz = EO_ALIGN_SIZE(sizeof(_Efl_Class));
2423
2424 _eo_classes = NULL;
2425 _eo_classes_last_id = EO_CLASS_IDS_FIRST - 1;
2426 _eo_log_dom = eina_log_domain_register(log_dom, EINA_COLOR_LIGHTBLUE);
2427 if (_eo_log_dom < 0)
2428 {
2429 EINA_LOG_ERR("Could not register log domain: %s.", log_dom);
2430 return EINA_FALSE;
2431 }
2432
2433 if (!eina_lock_recursive_new(&_efl_class_creation_lock))
2434 {
2435 ERR("Could not init lock.");
2436 return EINA_FALSE;
2437 }
2438
2439 if (!eina_spinlock_new(&_ops_storage_lock))
2440 {
2441 ERR("Could not init lock.");
2442 return EINA_FALSE;
2443 }
2444
2445 _eo_log_obj_init();
2446
2447 eina_magic_string_static_set(EO_EINA_MAGIC, EO_EINA_MAGIC_STR);
2448 eina_magic_string_static_set(EO_FREED_EINA_MAGIC,
2449 EO_FREED_EINA_MAGIC_STR);
2450 eina_magic_string_static_set(EO_CLASS_EINA_MAGIC,
2451 EO_CLASS_EINA_MAGIC_STR);
2452 #ifndef _WIN32
2453 _ops_storage = eina_hash_pointer_new(NULL);
2454 #else
2455 _ops_storage = eina_hash_string_superfast_new(NULL);
2456 #endif
2457
2458 _eo_table_data_shared = _eo_table_data_new(EFL_ID_DOMAIN_SHARED);
2459 if (!_eo_table_data_shared)
2460 {
2461 ERR("Could not allocate shared table data");
2462 return EINA_FALSE;
2463 }
2464 _eo_table_data_shared_data = _eo_table_data_shared->tables[EFL_ID_DOMAIN_SHARED];
2465
2466 // specially force eoid data to be creanted so we can switch it to domain 0
2467 Eo_Id_Data *data = _eo_table_data_new(EFL_ID_DOMAIN_MAIN);
2468 _eo_gdb_main_domain = data;
2469 if (!data)
2470 {
2471 ERR("Could not allocate main table data");
2472 return EINA_FALSE;
2473 }
2474 if (!eina_tls_cb_new(&_eo_table_data, _eo_table_del_cb))
2475 {
2476 ERR("Could not allocate TLS for eo domain data");
2477 _eo_table_del_cb(data);
2478 return EINA_FALSE;
2479 }
2480 eina_tls_set(_eo_table_data, data);
2481 _efl_object_main_thread = eina_thread_self();
2482
2483 efl_object_optional_cow =
2484 eina_cow_add("Efl Object Optional Data", sizeof(Efl_Object_Optional),
2485 64, &efl_object_optional_cow_default, EINA_TRUE);
2486
2487 _efl_add_fallback_init();
2488
2489 eina_log_timing(_eo_log_dom,
2490 EINA_LOG_STATE_STOP,
2491 EINA_LOG_STATE_INIT);
2492
2493 /* bootstrap EFL_CLASS_CLASS */
2494 const Eo *efl_klass = EFL_CLASS_CLASS;
2495 /* bootstrap EFL_OBJECT_CLASS */
2496 const Eo *efl_object = EFL_OBJECT_CLASS;
2497
2498 return efl_klass && efl_object;
2499 }
2500
2501 EAPI Eina_Bool
efl_object_shutdown(void)2502 efl_object_shutdown(void)
2503 {
2504 size_t i;
2505 _Efl_Class **cls_itr = _eo_classes + _eo_classes_last_id - 1;
2506
2507 if (--_efl_object_init_count > 0)
2508 return EINA_TRUE;
2509
2510 #ifdef EO_DEBUG
2511 {
2512 Efl_Object *obj;
2513 Eina_Iterator *objects;
2514 objects = eo_objects_iterator_new();
2515 printf("Objects leaked by EO:\n");
2516 printf("class@pointer - user-refcount internal-refcount\n");
2517 EINA_ITERATOR_FOREACH(objects, obj)
2518 {
2519 printf("%s@%p - %d %d \n", efl_class_name_get(obj), obj, efl_ref_count(obj), ___efl_ref2_count(obj));
2520 }
2521 eina_iterator_free(objects);
2522 }
2523 #endif
2524
2525
2526 eina_log_timing(_eo_log_dom,
2527 EINA_LOG_STATE_START,
2528 EINA_LOG_STATE_SHUTDOWN);
2529
2530 _efl_add_fallback_shutdown();
2531
2532 for (i = 0 ; i < _eo_classes_last_id ; i++, cls_itr--)
2533 {
2534 if (*cls_itr)
2535 eo_class_free(*cls_itr);
2536 }
2537
2538 eina_lock_take(&_efl_class_creation_lock);
2539 _eo_classes_release();
2540 eina_lock_release(&_efl_class_creation_lock);
2541
2542 eina_hash_free(_ops_storage);
2543 _ops_storage = NULL;
2544
2545 eina_spinlock_free(&_ops_storage_lock);
2546 eina_lock_free(&_efl_class_creation_lock);
2547
2548 _eo_free_ids_tables(_eo_table_data_get());
2549 eina_tls_free(_eo_table_data);
2550 if (_eo_table_data_shared)
2551 {
2552 _eo_free_ids_tables(_eo_table_data_shared);
2553 _eo_table_data_shared = NULL;
2554 _eo_table_data_shared_data = NULL;
2555 }
2556
2557 eina_cow_del(efl_object_optional_cow);
2558 efl_object_optional_cow = NULL;
2559
2560 _eo_log_obj_shutdown();
2561
2562 eina_log_domain_unregister(_eo_log_dom);
2563 _eo_log_dom = -1;
2564
2565 ++_efl_object_init_generation;
2566
2567 eina_shutdown();
2568 return EINA_FALSE;
2569 }
2570
2571
2572 EAPI Efl_Id_Domain
efl_domain_get(void)2573 efl_domain_get(void)
2574 {
2575 Eo_Id_Data *data = _eo_table_data_get();
2576 return data->local_domain;
2577 }
2578
2579 EAPI Efl_Id_Domain
efl_domain_current_get(void)2580 efl_domain_current_get(void)
2581 {
2582 Eo_Id_Data *data = _eo_table_data_get();
2583 return data->domain_stack[data->stack_top];
2584 }
2585
2586 EAPI Eina_Bool
efl_domain_switch(Efl_Id_Domain domain)2587 efl_domain_switch(Efl_Id_Domain domain)
2588 {
2589 Eo_Id_Data *data = _eo_table_data_get();
2590 Eo_Id_Data *new_data;
2591 if ((domain < EFL_ID_DOMAIN_MAIN) || (domain > EFL_ID_DOMAIN_THREAD) ||
2592 (domain == EFL_ID_DOMAIN_SHARED))
2593 {
2594 ERR("Invalid domain %i being switched to", domain);
2595 return EINA_FALSE;
2596 }
2597 if ((data) && (data->local_domain == domain))
2598 return EINA_TRUE;
2599
2600 new_data = _eo_table_data_new(domain);
2601 if (!new_data)
2602 {
2603 ERR("Could not allocate domain %i table data", domain);
2604 return EINA_FALSE;
2605 }
2606 if (data) _eo_free_ids_tables(data);
2607 new_data->local_domain = domain;
2608 new_data->domain_stack[new_data->stack_top] = domain;
2609 eina_tls_set(_eo_table_data, new_data);
2610 return EINA_TRUE;
2611 }
2612
2613 static inline Eina_Bool
_efl_domain_push(Eo_Id_Data * data,Efl_Id_Domain domain)2614 _efl_domain_push(Eo_Id_Data *data, Efl_Id_Domain domain)
2615 {
2616 if (data->stack_top >= (sizeof(data->domain_stack) - 1))
2617 {
2618 ERR("Failed to push domain %i on stack. Out of stack space at %i",
2619 domain, data->stack_top);
2620 return EINA_FALSE;
2621 }
2622 data->stack_top++;
2623 data->domain_stack[data->stack_top] = domain;
2624 return EINA_TRUE;
2625 }
2626
2627 static inline void
_efl_domain_pop(Eo_Id_Data * data)2628 _efl_domain_pop(Eo_Id_Data *data)
2629 {
2630 if (data->stack_top > 0) data->stack_top--;
2631 }
2632
2633 EAPI Eina_Bool
efl_domain_current_push(Efl_Id_Domain domain)2634 efl_domain_current_push(Efl_Id_Domain domain)
2635 {
2636 Eo_Id_Data *data = _eo_table_data_get();
2637 return _efl_domain_push(data, domain);
2638 }
2639
2640 EAPI void
efl_domain_current_pop(void)2641 efl_domain_current_pop(void)
2642 {
2643 Eo_Id_Data *data = _eo_table_data_get();
2644 _efl_domain_pop(data);
2645 }
2646
2647 EAPI Eina_Bool
efl_domain_current_set(Efl_Id_Domain domain)2648 efl_domain_current_set(Efl_Id_Domain domain)
2649 {
2650 Eo_Id_Data *data = _eo_table_data_get();
2651 if ((domain < EFL_ID_DOMAIN_MAIN) || (domain > EFL_ID_DOMAIN_THREAD))
2652 {
2653 ERR("Invalid domain %i being set", domain);
2654 return EINA_FALSE;
2655 }
2656 data->domain_stack[data->stack_top] = domain;
2657 return EINA_TRUE;
2658 }
2659
2660 EAPI Efl_Domain_Data *
efl_domain_data_get(void)2661 efl_domain_data_get(void)
2662 {
2663 Eo_Id_Data *data = _eo_table_data_get();
2664 return (Efl_Domain_Data *)data;
2665 }
2666
2667 EAPI Efl_Id_Domain
efl_domain_data_adopt(Efl_Domain_Data * data_in)2668 efl_domain_data_adopt(Efl_Domain_Data *data_in)
2669 {
2670 Eo_Id_Data *data = _eo_table_data_get();
2671 Eo_Id_Data *data_foreign = (Eo_Id_Data *)data_in;
2672
2673 if (!data_foreign)
2674 {
2675 ERR("Trying to adopt NULL domain data [data=%p in=%p]", data, data_in);
2676 return EFL_ID_DOMAIN_INVALID;
2677 }
2678 if (data_foreign->local_domain == data->local_domain)
2679 {
2680 ERR("Trying to adopt EO ID domain %i, is the same as the local %i [data=%p in=%p foreign=%p]",
2681 data_foreign->local_domain, data->local_domain, data, data_in, data_foreign);
2682 return EFL_ID_DOMAIN_INVALID;
2683 }
2684 if (data->tables[data_foreign->local_domain])
2685 {
2686 ERR("Trying to adopt an already adopted domain [data=%p in=%p foreign=%p]", data, data_in, data_foreign);
2687 return EFL_ID_DOMAIN_INVALID;
2688 }
2689 data->tables[data_foreign->local_domain] =
2690 data_foreign->tables[data_foreign->local_domain];
2691 _efl_domain_push(data, data_foreign->local_domain);
2692 return data->domain_stack[data->stack_top];
2693 }
2694
2695 EAPI Eina_Bool
efl_domain_data_return(Efl_Id_Domain domain)2696 efl_domain_data_return(Efl_Id_Domain domain)
2697 {
2698 Eo_Id_Data *data = _eo_table_data_get();
2699
2700 if ((domain < EFL_ID_DOMAIN_MAIN) || (domain > EFL_ID_DOMAIN_THREAD))
2701 {
2702 ERR("Invalid domain %i being returned to owning thread", domain);
2703 return EINA_FALSE;
2704 }
2705 if (domain == data->local_domain)
2706 {
2707 ERR("Cannot return the local domain %i back to its owner [data=%p]", domain, data);
2708 return EINA_FALSE;
2709 }
2710 data->tables[domain] = NULL;
2711 _efl_domain_pop(data);
2712 return EINA_TRUE;
2713 }
2714
2715 EAPI Eina_Bool
efl_compatible(const Eo * obj,const Eo * obj_target)2716 efl_compatible(const Eo *obj, const Eo *obj_target)
2717 {
2718 Efl_Id_Domain domain1 = ((Eo_Id)obj >> SHIFT_DOMAIN) & MASK_DOMAIN;
2719 Efl_Id_Domain domain2 = ((Eo_Id)obj_target >> SHIFT_DOMAIN) & MASK_DOMAIN;
2720 if (domain1 == domain2) return EINA_TRUE;
2721 DBG("Object %p and %p are not compatible. Domain %i and %i do not match",
2722 obj, obj_target, domain1, domain2);
2723 return EINA_FALSE;
2724 }
2725
2726 EAPI Eina_Bool
efl_class_override_register(const Efl_Class * klass,const Efl_Class * override)2727 efl_class_override_register(const Efl_Class *klass, const Efl_Class *override)
2728 {
2729 EINA_SAFETY_ON_NULL_RETURN_VAL(klass, EINA_FALSE);
2730 EINA_SAFETY_ON_NULL_RETURN_VAL(override, EINA_FALSE);
2731 EINA_SAFETY_ON_TRUE_RETURN_VAL(!efl_isa(override, klass), EINA_FALSE);
2732 if (!class_overrides)
2733 class_overrides = eina_hash_pointer_new(NULL);
2734 EINA_SAFETY_ON_NULL_RETURN_VAL(class_overrides, EINA_FALSE);
2735
2736 eina_hash_set(class_overrides, &klass, override);
2737 return EINA_TRUE;
2738 }
2739
2740 EAPI Eina_Bool
efl_class_override_unregister(const Efl_Class * klass,const Efl_Class * override)2741 efl_class_override_unregister(const Efl_Class *klass, const Efl_Class *override)
2742 {
2743 const Efl_Class *set;
2744 EINA_SAFETY_ON_NULL_RETURN_VAL(klass, EINA_FALSE);
2745 EINA_SAFETY_ON_NULL_RETURN_VAL(override, EINA_FALSE);
2746 if (!class_overrides) return EINA_TRUE;
2747
2748 set = eina_hash_find(class_overrides, &klass);
2749 if (set != override) return EINA_FALSE;
2750 return eina_hash_del_by_key(class_overrides, &klass);
2751 }
2752
2753 EAPI Eina_Bool
efl_destructed_is(const Eo * obj_id)2754 efl_destructed_is(const Eo *obj_id)
2755 {
2756 Eina_Bool is;
2757 EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, EINA_FALSE);
2758 is = obj->destructed;
2759 EO_OBJ_DONE(obj_id);
2760 return is;
2761 }
2762
2763 EAPI void
efl_manual_free_set(Eo * obj_id,Eina_Bool manual_free)2764 efl_manual_free_set(Eo *obj_id, Eina_Bool manual_free)
2765 {
2766 EO_OBJ_POINTER_RETURN(obj_id, obj);
2767 obj->manual_free = manual_free;
2768 EO_OBJ_DONE(obj_id);
2769 }
2770
2771 EAPI Eina_Bool
efl_manual_free(Eo * obj_id)2772 efl_manual_free(Eo *obj_id)
2773 {
2774 EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, EINA_FALSE);
2775
2776 // rare to use goto to keep instruction cache cleaner
2777 if (obj->manual_free == EINA_FALSE) goto err_manual_free;
2778 // rare to use goto to keep instruction cache cleaner
2779 if (!obj->destructed) goto err_not_destructed;
2780 _eo_free(obj, EINA_TRUE);
2781 EO_OBJ_DONE(obj_id);
2782 return EINA_TRUE;
2783
2784 err_manual_free:
2785 ERR("Tried to manually free the object %p while the option has not been set; see efl_manual_free_set for more information.", obj);
2786 goto err;
2787 err_not_destructed:
2788 ERR("Tried deleting the object %p while still referenced(%d).", obj_id, obj->refcount);
2789 goto err;
2790 err:
2791 EO_OBJ_DONE(obj_id);
2792 return EINA_FALSE;
2793 }
2794
2795 EAPI const char *
efl_debug_name_get(const Eo * obj_id)2796 efl_debug_name_get(const Eo *obj_id)
2797 {
2798 const char *override = "";
2799 const char *name, *clsname;
2800 Eina_Strbuf *sb;
2801
2802 if (!obj_id) return "(null)";
2803
2804 if (_eo_is_a_class(obj_id))
2805 {
2806 const char *clstype;
2807
2808 EO_CLASS_POINTER(obj_id, klass);
2809 if (!klass || !klass->desc)
2810 return eina_slstr_printf("Invalid_Class_ID(invalid)@%p", obj_id);
2811
2812 switch (klass->desc->type)
2813 {
2814 case EFL_CLASS_TYPE_REGULAR: clstype = "regular"; break;
2815 case EFL_CLASS_TYPE_REGULAR_NO_INSTANT: clstype = "abstract"; break;
2816 case EFL_CLASS_TYPE_INTERFACE: clstype = "interface"; break;
2817 case EFL_CLASS_TYPE_MIXIN: clstype = "mixin"; break;
2818 default: clstype = "invalid"; break;
2819 }
2820
2821 return eina_slstr_printf("%s(%s)@%p", klass->desc->name, clstype, obj_id);
2822 }
2823
2824 EO_OBJ_POINTER(obj_id, obj);
2825 if (!obj) return eina_slstr_printf("Invalid_Object_ID@%p", obj_id);
2826
2827 sb = eina_strbuf_new();
2828 name = efl_name_get(obj_id);
2829 clsname = obj->klass->desc->name;
2830 if (_obj_is_override(obj)) override = "(override)";
2831
2832 if (name)
2833 eina_strbuf_append_printf(sb, "%s%s@%p[%d]:'%s'", clsname, override, obj_id, (int) obj->refcount, name);
2834 else
2835 eina_strbuf_append_printf(sb, "%s%s@%p[%d]", clsname, override, obj_id, (int) obj->refcount);
2836
2837 if (!obj->cur_klass)
2838 {
2839 efl_debug_name_override((Eo *) obj_id, sb);
2840 }
2841 else
2842 {
2843 if (obj->super)
2844 efl_debug_name_override(efl_super(obj_id, (Efl_Class *) obj->cur_klass->header.id), sb);
2845 else
2846 efl_debug_name_override(efl_cast(obj_id, (Efl_Class *) obj->cur_klass->header.id), sb);
2847 obj->super = EINA_FALSE;
2848 obj->cur_klass = NULL;
2849 }
2850
2851 EO_OBJ_DONE(obj_id);
2852 return eina_slstr_strbuf_new(sb);
2853 }
2854
2855 EAPI int
efl_callbacks_cmp(const Efl_Callback_Array_Item * a,const Efl_Callback_Array_Item * b)2856 efl_callbacks_cmp(const Efl_Callback_Array_Item *a, const Efl_Callback_Array_Item *b)
2857 {
2858 if (a->desc == b->desc) return 0;
2859 else if (a->desc > b->desc) return 1;
2860 else return -1;
2861 }
2862
2863
2864 #ifdef EO_DEBUG
2865 /* NOTE: cannot use ecore_time_get()! */
2866 static inline double
_eo_log_time_now(void)2867 _eo_log_time_now(void)
2868 {
2869 #ifdef _WIN32
2870 return evil_time_get();
2871 #elif defined(__APPLE__) && defined(__MACH__)
2872 static double clk_conv = -1.0;
2873
2874 if (EINA_UNLIKELY(clk_conv < 0))
2875 {
2876 mach_timebase_info_data_t info;
2877 kern_return_t err = mach_timebase_info(&info);
2878 if (err == 0)
2879 clk_conv = 1e-9 * (double)info.numer / (double)info.denom;
2880 else
2881 clk_conv = 1e-9;
2882 }
2883
2884 return clk_conv * mach_absolute_time();
2885 #else
2886 #if defined (HAVE_CLOCK_GETTIME)
2887 struct timespec t;
2888 static int clk_id = -1;
2889
2890 if (EINA_UNLIKELY(clk_id == -2)) goto try_gettimeofday;
2891 if (EINA_UNLIKELY(clk_id == -1))
2892 {
2893 retry_clk_id:
2894 clk_id = CLOCK_MONOTONIC;
2895 if (EINA_UNLIKELY(clock_gettime(clk_id, &t)))
2896 {
2897 WRN("CLOCK_MONOTONIC failed!");
2898 clk_id = CLOCK_REALTIME;
2899 if (EINA_UNLIKELY(clock_gettime(clk_id, &t)))
2900 {
2901 WRN("CLOCK_REALTIME failed!");
2902 clk_id = -2;
2903 goto try_gettimeofday;
2904 }
2905 }
2906 }
2907 else
2908 {
2909 if (EINA_UNLIKELY(clock_gettime(clk_id, &t)))
2910 {
2911 WRN("clk_id=%d previously ok, now failed... retry", clk_id);
2912 goto retry_clk_id;
2913 }
2914 }
2915 return (double)t.tv_sec + (((double)t.tv_nsec) / 1000000000.0);
2916
2917 try_gettimeofday:
2918 #endif
2919 {
2920 struct timeval timev;
2921
2922 gettimeofday(&timev, NULL);
2923 return (double)timev.tv_sec + (((double)timev.tv_usec) / 1000000);
2924 }
2925 #endif
2926 }
2927
2928 #ifdef HAVE_BACKTRACE
2929 typedef struct _Eo_Log_Obj_Entry {
2930 Eo_Id id;
2931 const _Eo_Object *obj;
2932 const _Efl_Class *klass;
2933 double timestamp;
2934 Eo_Ref_Op ref_op;
2935 unsigned bt_size;
2936 unsigned bt_hits;
2937 uintptr_t bt_hash;
2938 void *bt[];
2939 } Eo_Log_Obj_Entry;
2940
2941 static void
_eo_log_obj_find(const Eo_Id id,const Eo_Log_Obj_Entry ** added,int * added_idx,const Eo_Log_Obj_Entry ** deleted)2942 _eo_log_obj_find(const Eo_Id id, const Eo_Log_Obj_Entry **added, int *added_idx, const Eo_Log_Obj_Entry **deleted)
2943 {
2944 const Eo_Log_Obj_Entry *entry;
2945 Eina_Array_Iterator it;
2946 unsigned int idx;
2947
2948 *added_idx = -1;
2949 *added = NULL;
2950 *deleted = NULL;
2951
2952 eina_spinlock_take(&_eo_log_objs_lock);
2953 EINA_ARRAY_ITER_NEXT(&_eo_log_objs, idx, entry, it)
2954 {
2955 if (EINA_UNLIKELY(id == entry->id))
2956 {
2957 if (entry->ref_op == EO_REF_OP_FREE)
2958 *deleted = entry;
2959 else if (entry->ref_op == EO_REF_OP_NEW)
2960 {
2961 *added_idx = idx;
2962 *added = entry;
2963 *deleted = NULL; /* forget previous add, if any */
2964 }
2965 }
2966 }
2967 eina_spinlock_release(&_eo_log_objs_lock);
2968 }
2969
2970 static void
_eo_log_obj_entry_show(const Eo_Log_Obj_Entry * entry,int log_level,const char * func_name,const char * file,int line,double now)2971 _eo_log_obj_entry_show(const Eo_Log_Obj_Entry *entry, int log_level, const char *func_name, const char *file, int line, double now)
2972 {
2973 unsigned i;
2974
2975 eina_log_print(_eo_log_objs_dom, log_level, file, func_name, line,
2976 "%s obj_id=%p obj=%p, class=%p (%s) [%0.4fs, %0.4fs ago] [%d hits]:",
2977 _eo_ref_op_str[entry->ref_op],
2978 (void *)entry->id,
2979 entry->obj,
2980 entry->klass,
2981 entry->klass->desc->name,
2982 entry->timestamp - _eo_log_time_start, now - entry->timestamp,
2983 entry->bt_hits);
2984
2985 // Skip EAPI and _eo_log_obj_ref_op()
2986 for (i = 2; i < entry->bt_size; i++)
2987 {
2988 #ifdef HAVE_DLADDR
2989 Dl_info info;
2990
2991 if (dladdr(entry->bt[i], &info))
2992 {
2993 if (info.dli_sname)
2994 {
2995 eina_log_print(_eo_log_objs_dom, log_level, file, func_name, line,
2996 " 0x%016llx: %s+%llu (in %s 0x%llx)",
2997 (unsigned long long)(uintptr_t)entry->bt[i],
2998 info.dli_sname,
2999 (unsigned long long)(uintptr_t)((char *)entry->bt[i] - (char *)info.dli_saddr),
3000 info.dli_fname ? info.dli_fname : "??",
3001 (unsigned long long)(uintptr_t)info.dli_fbase);
3002 continue;
3003 }
3004 else if (info.dli_fname)
3005 {
3006 const char *fname;
3007
3008 #ifdef _WIN32
3009 fname = strrchr(info.dli_fname, '\\');
3010 #else
3011 fname = strrchr(info.dli_fname, '/');
3012 #endif
3013 if (!fname) fname = info.dli_fname;
3014 else fname++;
3015
3016 eina_log_print(_eo_log_objs_dom, log_level, file, func_name, line,
3017 " 0x%016llx: %s+%llu (in %s 0x%llx)",
3018 (unsigned long long)(uintptr_t)entry->bt[i],
3019 fname,
3020 (unsigned long long)(uintptr_t)((char *)entry->bt[i] - (char *)info.dli_fbase),
3021 info.dli_fname,
3022 (unsigned long long)(uintptr_t)info.dli_fbase);
3023 continue;
3024 }
3025 }
3026 #endif
3027
3028 eina_log_print(_eo_log_objs_dom, log_level, func_name, file, line,
3029 " 0x%016llx", (unsigned long long)(uintptr_t)entry->bt[i]);
3030 }
3031 }
3032 #endif
3033
3034 #ifdef HAVE_BACKTRACE
3035 static uintptr_t
_eo_log_obj_backtrace_hash(Eo_Log_Obj_Entry * entry)3036 _eo_log_obj_backtrace_hash(Eo_Log_Obj_Entry *entry)
3037 {
3038 if (!entry->bt_hash)
3039 {
3040 entry->bt_hash = (uintptr_t) 4294967291;
3041 for (unsigned k = 0; k < entry->bt_size; k++)
3042 entry->bt_hash ^= ((uintptr_t) (entry->bt[k]));
3043 }
3044
3045 return entry->bt_hash;
3046 }
3047
3048 static Eina_Bool
_eo_log_obj_entry_is_new_backtrace(const Eina_List * entries,Eo_Log_Obj_Entry * entry)3049 _eo_log_obj_entry_is_new_backtrace(const Eina_List *entries, Eo_Log_Obj_Entry *entry)
3050 {
3051 Eina_Bool ret = EINA_TRUE;
3052 Eo_Log_Obj_Entry *other;
3053 const Eina_List *li;
3054 uintptr_t hash;
3055
3056 hash = _eo_log_obj_backtrace_hash(entry);
3057 EINA_LIST_FOREACH(entries, li, other)
3058 if (_eo_log_obj_backtrace_hash(other) == hash)
3059 {
3060 other->bt_hits++;
3061 ret = EINA_FALSE;
3062 }
3063
3064 return ret;
3065 }
3066
3067 static Eina_List *
_eo_log_obj_find_all(const Eo_Id id,int start_idx)3068 _eo_log_obj_find_all(const Eo_Id id, int start_idx)
3069 {
3070 Eo_Log_Obj_Entry *entry;
3071 Eina_List *entries = NULL;
3072 unsigned int idx;
3073
3074 eina_spinlock_take(&_eo_log_objs_lock);
3075 for (idx = start_idx + 1; idx < eina_array_count(&_eo_log_objs); idx++)
3076 {
3077 entry = eina_array_data_get(&_eo_log_objs, idx);
3078 if (entry->id != id) continue;
3079 if (entry->ref_op > _eo_log_objs_level) continue;
3080 if (entry->ref_op == EO_REF_OP_FREE) break;
3081 if (_eo_log_obj_entry_is_new_backtrace(entries, entry))
3082 entries = eina_list_append(entries, entry);
3083 }
3084 eina_spinlock_release(&_eo_log_objs_lock);
3085 return entries;
3086 }
3087 #endif
3088
3089 inline void
_eo_log_obj_report(const Eo_Id id,int log_level,const char * func_name,const char * file,int line)3090 _eo_log_obj_report(const Eo_Id id, int log_level, const char *func_name, const char *file, int line)
3091 {
3092 #ifdef HAVE_BACKTRACE
3093 const Eo_Log_Obj_Entry *added, *deleted;
3094 Eo_Log_Obj_Entry *current = NULL;
3095 int added_idx = -1;
3096 double now;
3097
3098 if (EINA_LIKELY(!_eo_log_objs_level)) return;
3099
3100 _eo_log_obj_find(id, &added, &added_idx, &deleted);
3101
3102 if ((!added) && (!deleted))
3103 {
3104 if ((!_eo_log_objs_debug.len) && (!_eo_log_objs_no_debug.len))
3105 {
3106 eina_log_print(_eo_log_objs_dom, log_level, file, func_name, line,
3107 "obj_id=%p was neither created or deleted.", (void *)id);
3108 }
3109 else if ((_eo_log_objs_debug.len) && (_eo_log_objs_no_debug.len))
3110 {
3111 eina_log_print(_eo_log_objs_dom, log_level, file, func_name, line,
3112 "obj_id=%p was neither created or deleted (EO_LIFECYCLE_DEBUG='%s', EO_LIFECYCLE_NO_DEBUG='%s').",
3113 (void *)id, getenv("EO_LIFECYCLE_DEBUG"), getenv("EO_LIFECYCLE_NO_DEBUG"));
3114 }
3115 else if (_eo_log_objs_debug.len)
3116 {
3117 eina_log_print(_eo_log_objs_dom, log_level, file, func_name, line,
3118 "obj_id=%p was neither created or deleted (EO_LIFECYCLE_DEBUG='%s').",
3119 (void *)id, getenv("EO_LIFECYCLE_DEBUG"));
3120 }
3121 else
3122 {
3123 eina_log_print(_eo_log_objs_dom, log_level, file, func_name, line,
3124 "obj_id=%p was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='%s').",
3125 (void *)id, getenv("EO_LIFECYCLE_NO_DEBUG"));
3126 }
3127 return;
3128 }
3129
3130 now = _eo_log_time_now();
3131
3132 #ifdef HAVE_BACKTRACE
3133 if ((_eo_log_objs_backtrace >= 0) && deleted)
3134 {
3135 void **bt = NULL;
3136 int size = 0;
3137
3138 if (_eo_log_objs_backtrace > 0)
3139 {
3140 bt = alloca(sizeof(void *) * (_eo_log_objs_backtrace + 2));
3141 size = backtrace(bt, (_eo_log_objs_backtrace + 2));
3142 if (EINA_UNLIKELY(size < 1))
3143 {
3144 bt = NULL;
3145 size = 0;
3146 }
3147 }
3148
3149 current = calloc(1, sizeof(Eo_Log_Obj_Entry) + size * sizeof(void *));
3150 if (EINA_UNLIKELY(!current)) return;
3151
3152 current->id = id;
3153 current->timestamp = now;
3154 current->obj = deleted->obj;
3155 current->klass = deleted->klass;
3156 current->ref_op = EO_REF_OP_NONE;
3157 current->bt_size = size;
3158 current->bt_hash = 0;
3159 current->bt_hits = 1;
3160 if (bt && size)
3161 memcpy(current->bt, bt, size * sizeof(void *));
3162 }
3163 #endif
3164
3165 if (added)
3166 {
3167 _eo_log_obj_entry_show(added, log_level, func_name, file, line, now);
3168
3169 if (_eo_log_objs_level > EO_REF_OP_FREE)
3170 {
3171 Eina_List *entries = _eo_log_obj_find_all(id, added_idx);
3172 const Eo_Log_Obj_Entry *entry;
3173
3174 EINA_LIST_FREE(entries, entry)
3175 _eo_log_obj_entry_show(entry, log_level, func_name, file, line, now);
3176 }
3177 }
3178
3179 if (deleted)
3180 {
3181 _eo_log_obj_entry_show(deleted, log_level, func_name, file, line, now);
3182 eina_log_print(_eo_log_objs_dom, log_level, file, func_name, line,
3183 "obj_id=%p was already deleted %0.4f seconds ago!",
3184 (void *)id, now - deleted->timestamp);
3185 }
3186
3187 if (current)
3188 {
3189 eina_log_print(_eo_log_objs_dom, log_level, file, func_name, line,
3190 "obj_id=%p current use from:", (void *)id);
3191 _eo_log_obj_entry_show(current, log_level, func_name, file, line, now);
3192 free(current);
3193 }
3194
3195 #else
3196 (void)id;
3197 (void)log_level;
3198 (void)func_name;
3199 (void)file;
3200 (void)line;
3201 #endif
3202 }
3203
3204 #ifdef HAVE_BACKTRACE
3205 static Eo_Log_Obj_Entry *
_eo_log_obj_entry_ref_op(const _Eo_Object * obj,Eo_Ref_Op refop,unsigned size,void * const * bt)3206 _eo_log_obj_entry_ref_op(const _Eo_Object *obj, Eo_Ref_Op refop, unsigned size, void *const *bt)
3207 {
3208 Eo_Log_Obj_Entry *entry;
3209 Eina_Bool ret;
3210
3211 entry = calloc(1, sizeof(Eo_Log_Obj_Entry) + size * sizeof(void *));
3212 if (EINA_UNLIKELY(!entry)) return NULL;
3213
3214 entry->id = (Eo_Id)_eo_obj_id_get(obj);
3215 entry->timestamp = _eo_log_time_now();
3216 entry->obj = obj;
3217 entry->klass = obj->klass;
3218 entry->ref_op = refop;
3219 entry->bt_size = size;
3220 entry->bt_hash = 0;
3221 entry->bt_hits = 1;
3222 if (size && bt)
3223 memcpy(entry->bt, bt, size * sizeof(void *));
3224
3225 eina_spinlock_take(&_eo_log_objs_lock);
3226 ret = eina_array_push(&_eo_log_objs, entry);
3227 eina_spinlock_release(&_eo_log_objs_lock);
3228 if (!ret)
3229 {
3230 free(entry);
3231 return NULL;
3232 }
3233
3234 return entry;
3235 }
3236
3237 static inline void
_eo_log_obj_entry_free(Eo_Log_Obj_Entry * entry)3238 _eo_log_obj_entry_free(Eo_Log_Obj_Entry *entry)
3239 {
3240 free(entry);
3241 }
3242 #endif
3243
3244 static int
_eo_class_name_slice_cmp(const void * pa,const void * pb)3245 _eo_class_name_slice_cmp(const void *pa, const void *pb)
3246 {
3247 const Eina_Slice *a = pa;
3248 const Eina_Slice *b = pb;
3249
3250 if (a->len < b->len) return -1;
3251 if (a->len > b->len) return 1;
3252 return memcmp(a->mem, b->mem, a->len);
3253 }
3254
3255 static Eina_Bool
_eo_log_obj_desired(const _Eo_Object * obj)3256 _eo_log_obj_desired(const _Eo_Object *obj)
3257 {
3258 Eina_Slice cls_name;
3259
3260 if (EINA_LIKELY((_eo_log_objs_debug.len == 0) &&
3261 (_eo_log_objs_no_debug.len == 0)))
3262 return EINA_TRUE;
3263
3264 cls_name.mem = obj->klass->desc->name;
3265 cls_name.len = strlen(cls_name.mem);
3266
3267 if (_eo_log_objs_no_debug.len)
3268 {
3269 if (eina_inarray_search_sorted(&_eo_log_objs_no_debug, &cls_name, _eo_class_name_slice_cmp) >= 0)
3270 return EINA_FALSE;
3271 }
3272
3273 if (!_eo_log_objs_debug.len)
3274 return EINA_TRUE;
3275
3276 if (eina_inarray_search_sorted(&_eo_log_objs_debug, &cls_name, _eo_class_name_slice_cmp) >= 0)
3277 return EINA_TRUE;
3278
3279 return EINA_FALSE;
3280 }
3281
3282 static void
_eo_log_obj_ref_op(const _Eo_Object * obj,Eo_Ref_Op ref_op)3283 _eo_log_obj_ref_op(const _Eo_Object *obj, Eo_Ref_Op ref_op)
3284 {
3285 if (EINA_LIKELY(_eo_log_objs_level < ref_op)) return;
3286 if (EINA_LIKELY(!_eo_log_obj_desired(obj))) return;
3287
3288 #ifdef HAVE_BACKTRACE
3289 if (_eo_log_objs_backtrace >= 0)
3290 {
3291 void **bt = NULL;
3292 int size = 0;
3293
3294 if (_eo_log_objs_backtrace > 0)
3295 {
3296 bt = alloca(sizeof(void *) * (_eo_log_objs_backtrace + 2));
3297 size = backtrace(bt, (_eo_log_objs_backtrace + 2));
3298 if (EINA_UNLIKELY(size < 1)) return;
3299 }
3300
3301 _eo_log_obj_entry_ref_op(obj, ref_op, size, bt);
3302 }
3303 #endif
3304
3305 EINA_LOG_DOM_DBG(_eo_log_objs_dom,
3306 "%s obj_id=%p class=%p (%s) [%0.4f]",
3307 _eo_ref_op_str[ref_op], _eo_obj_id_get(obj),
3308 obj->klass, obj->klass->desc->name,
3309 _eo_log_time_now() - _eo_log_time_start);
3310 }
3311
3312 static inline void
_eo_log_obj_init(void)3313 _eo_log_obj_init(void)
3314 {
3315 const char *s;
3316
3317 _eo_log_objs_dom = eina_log_domain_register("eo_lifecycle", EINA_COLOR_BLUE);
3318 _eo_log_time_start = _eo_log_time_now();
3319
3320 #ifdef HAVE_BACKTRACE
3321 eina_array_step_set(&_eo_log_objs, sizeof(Eina_Array), 4096);
3322 eina_spinlock_new(&_eo_log_objs_lock);
3323 #endif
3324 eina_inarray_step_set(&_eo_log_objs_debug, sizeof(Eina_Inarray), sizeof(Eina_Slice), 0);
3325 eina_inarray_step_set(&_eo_log_objs_no_debug, sizeof(Eina_Inarray), sizeof(Eina_Slice), 0);
3326
3327 s = getenv("EO_LIFECYCLE_BACKTRACE");
3328 if (s && *s)
3329 {
3330 _eo_log_objs_backtrace = atoi(s);
3331 if (_eo_log_objs_backtrace > EO_LOG_OBJS_BACKTRACE_MAX)
3332 _eo_log_objs_backtrace = EO_LOG_OBJS_BACKTRACE_MAX;
3333 else if (_eo_log_objs_backtrace < 0)
3334 _eo_log_objs_backtrace = 0;
3335 }
3336 else
3337 _eo_log_objs_backtrace = EO_LOG_OBJS_BACKTRACE_DEFAULT;
3338
3339 s = getenv("EO_LIFECYCLE_DEBUG");
3340 if ((s) && (s[0] != '\0'))
3341 {
3342 char *es;
3343 int lvl = (int)strtol(s, &es, 10);
3344 _eo_log_objs_level = EO_REF_OP_FREE;
3345 if ((es != s) && (*es == ':'))
3346 {
3347 if (lvl >= 3)
3348 {
3349 _eo_log_objs_level = EO_REF_OP_REUSE;
3350 EINA_LOG_DOM_DBG(_eo_log_objs_dom,
3351 "will log new, free, ref, unref and reuse");
3352 }
3353 else if (lvl == 2)
3354 {
3355 _eo_log_objs_level = EO_REF_OP_UNREF;
3356 EINA_LOG_DOM_DBG(_eo_log_objs_dom,
3357 "will log new, free, ref and unref");
3358 }
3359 s = es + 1;
3360 }
3361
3362 if ((strcmp(s, "*") == 0) || (strcmp(s, "1") == 0))
3363 {
3364 EINA_LOG_DOM_DBG(_eo_log_objs_dom,
3365 "will log all object allocation and free");
3366 }
3367 else
3368 {
3369 Eina_Slice slice;
3370 const Eina_Slice *itr;
3371 do
3372 {
3373 char *p = strchr(s, ',');
3374 slice.mem = s;
3375 if (p)
3376 {
3377 slice.len = p - s;
3378 s = p + 1;
3379 }
3380 else
3381 {
3382 slice.len = strlen(s);
3383 s = NULL;
3384 }
3385 eina_inarray_push(&_eo_log_objs_debug, &slice);
3386 }
3387 while (s);
3388 eina_inarray_sort(&_eo_log_objs_debug, _eo_class_name_slice_cmp);
3389
3390 EINA_INARRAY_FOREACH(&_eo_log_objs_debug, itr)
3391 {
3392 EINA_LOG_DOM_DBG(_eo_log_objs_dom,
3393 "will log class '" EINA_SLICE_STR_FMT "'",
3394 EINA_SLICE_STR_PRINT(*itr));
3395 }
3396 }
3397 #ifndef HAVE_BACKTRACE
3398 WRN("EO_LIFECYCLE_DEBUG='%s' but your system has no backtrace()!", s);
3399 #endif
3400 }
3401
3402 if (EINA_LIKELY(!_eo_log_objs_level)) return;
3403
3404 DBG("logging object allocation and free, use EINA_LOG_LEVELS=eo_lifecycle:4");
3405
3406 s = getenv("EO_LIFECYCLE_NO_DEBUG");
3407 if ((s) && (s[0] != '\0'))
3408 {
3409 if ((strcmp(s, "*") == 0) || (strcmp(s, "1") == 0))
3410 {
3411 EINA_LOG_DOM_ERR(_eo_log_objs_dom,
3412 "expected class names to not log allocation and free, got '%s'", s);
3413 }
3414 else
3415 {
3416 Eina_Slice slice;
3417 const Eina_Slice *itr;
3418 do
3419 {
3420 char *p = strchr(s, ',');
3421 slice.mem = s;
3422 if (p)
3423 {
3424 slice.len = p - s;
3425 s = p + 1;
3426 }
3427 else
3428 {
3429 slice.len = strlen(s);
3430 s = NULL;
3431 }
3432 eina_inarray_push(&_eo_log_objs_no_debug, &slice);
3433 }
3434 while (s);
3435 eina_inarray_sort(&_eo_log_objs_no_debug, _eo_class_name_slice_cmp);
3436
3437 EINA_INARRAY_FOREACH(&_eo_log_objs_no_debug, itr)
3438 {
3439 EINA_LOG_DOM_DBG(_eo_log_objs_dom,
3440 "will NOT log class '" EINA_SLICE_STR_FMT "'",
3441 EINA_SLICE_STR_PRINT(*itr));
3442 }
3443 }
3444 }
3445 }
3446
3447 static inline void
_eo_log_obj_shutdown(void)3448 _eo_log_obj_shutdown(void)
3449 {
3450 #ifdef HAVE_BACKTRACE
3451 Eo_Log_Obj_Entry *entry;
3452 Eina_Array_Iterator it;
3453 unsigned int idx;
3454
3455 eina_spinlock_take(&_eo_log_objs_lock);
3456 if (eina_log_domain_level_check(_eo_log_objs_dom, EINA_LOG_LEVEL_INFO))
3457 {
3458 void * const *itr = _eo_log_objs.data;
3459 void * const *itr_end = itr + _eo_log_objs.count;
3460 double now = _eo_log_time_now();
3461 size_t leaks = 0;
3462
3463 for (; itr < itr_end; itr++)
3464 {
3465 void * const *cur;
3466 entry = *itr;
3467 if (entry->ref_op == EO_REF_OP_FREE) continue;
3468 for (cur = itr + 1; cur < itr_end; cur++)
3469 {
3470 const Eo_Log_Obj_Entry *cur_entry = *cur;
3471 if (EINA_UNLIKELY((cur_entry->id == entry->id) && (cur_entry->ref_op == EO_REF_OP_FREE)))
3472 break;
3473 }
3474 if (EINA_UNLIKELY(cur == itr_end))
3475 {
3476 EINA_LOG_DOM_INFO(_eo_log_objs_dom,
3477 "leaking obj_id=%p obj=%p class=%p (%s) [%0.4fs, %0.4f ago]",
3478 (void *)entry->id,
3479 entry->obj,
3480 entry->klass,
3481 entry->klass->desc->name,
3482 entry->timestamp - _eo_log_time_start, now - entry->timestamp);
3483 _eo_log_obj_entry_show(entry, EINA_LOG_LEVEL_DBG, __func__, __FILE__, __LINE__, now);
3484 leaks++;
3485 }
3486 }
3487 if (leaks)
3488 EINA_LOG_DOM_WARN(_eo_log_objs_dom, "Leaked %zd objects! Check details with EINA_LOG_LEVELS=eo_lifecycle:4", leaks);
3489 else
3490 EINA_LOG_DOM_INFO(_eo_log_objs_dom, "No leaked objects!");
3491 }
3492 EINA_ARRAY_ITER_NEXT(&_eo_log_objs, idx, entry, it)
3493 _eo_log_obj_entry_free(entry);
3494 eina_array_flush(&_eo_log_objs);
3495 eina_spinlock_release(&_eo_log_objs_lock);
3496 eina_spinlock_free(&_eo_log_objs_lock);
3497 #endif
3498
3499 eina_inarray_flush(&_eo_log_objs_debug);
3500 eina_inarray_flush(&_eo_log_objs_no_debug);
3501 }
3502 #endif
3503
3504 typedef struct
3505 {
3506 Eina_Iterator iterator;
3507 unsigned int cur_kl_id;
3508 } _Eo_Classes_Iterator;
3509
3510 static Eina_Bool
_eo_classes_iterator_next(Eina_Iterator * it,void ** data)3511 _eo_classes_iterator_next(Eina_Iterator *it, void **data)
3512 {
3513 _Eo_Classes_Iterator *eo_it = (_Eo_Classes_Iterator *)it;
3514
3515 if (eo_it->cur_kl_id == _eo_classes_last_id) return EINA_FALSE;
3516 *data = _eo_class_id_get(_eo_classes[eo_it->cur_kl_id]);
3517 eo_it->cur_kl_id++;
3518 return EINA_TRUE;
3519 }
3520
3521 static void
_eo_classes_iterator_free(Eina_Iterator * it)3522 _eo_classes_iterator_free(Eina_Iterator *it)
3523 {
3524 EINA_MAGIC_SET(it, EINA_MAGIC_NONE);
3525 free(it);
3526 }
3527
3528 EAPI Eina_Iterator *
eo_classes_iterator_new(void)3529 eo_classes_iterator_new(void)
3530 {
3531 _Eo_Classes_Iterator *it;
3532
3533 it = calloc(1, sizeof (*it));
3534 if (!it) return NULL;
3535
3536 it->iterator.version = EINA_ITERATOR_VERSION;
3537 it->iterator.next = _eo_classes_iterator_next;
3538 it->iterator.free = _eo_classes_iterator_free;
3539 EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
3540
3541 return (Eina_Iterator *)it;
3542 }
3543
3544 typedef struct
3545 {
3546 Eina_Iterator iterator;
3547 Eo_Id_Table_Data *tdata;
3548 Table_Index mid_table_id;
3549 Table_Index table_id;
3550 Table_Index entry_id;
3551 } _Eo_Objects_Iterator;
3552
3553 static Eina_Bool
_eo_objects_iterator_next(Eina_Iterator * it,void ** data)3554 _eo_objects_iterator_next(Eina_Iterator *it, void **data)
3555 {
3556 Table_Index mid_table_id, table_id, entry_id;
3557 Eo_Id_Table_Data *tdata;
3558 _Eo_Objects_Iterator *eo_it = (_Eo_Objects_Iterator *)it;
3559 if (!eo_it->tdata) return EINA_FALSE;
3560
3561 tdata = eo_it->tdata;
3562 mid_table_id = eo_it->mid_table_id;
3563 table_id = eo_it->table_id;
3564 entry_id = eo_it->entry_id;
3565 while (mid_table_id < MAX_MID_TABLE_ID)
3566 {
3567 if (tdata->eo_ids_tables[mid_table_id])
3568 {
3569 while (table_id < MAX_TABLE_ID)
3570 {
3571 if (TABLE_FROM_IDS)
3572 {
3573 while (entry_id < MAX_ENTRY_ID)
3574 {
3575 _Eo_Id_Entry *entry = &(TABLE_FROM_IDS->entries[entry_id]);
3576 if (entry->active)
3577 {
3578 Eo *obj = _eo_header_id_get((Eo_Header *) entry->ptr);
3579 *data = obj;
3580 eo_it->mid_table_id = mid_table_id;
3581 eo_it->table_id = table_id;
3582 eo_it->entry_id = entry_id + 1;
3583 return EINA_TRUE;
3584 }
3585 entry_id++;
3586 }
3587 entry_id = 0;
3588 }
3589 table_id++;
3590 }
3591 table_id = 0;
3592 }
3593 mid_table_id++;
3594 }
3595 return EINA_FALSE;
3596 }
3597
3598 static void
_eo_objects_iterator_free(Eina_Iterator * it)3599 _eo_objects_iterator_free(Eina_Iterator *it)
3600 {
3601 EINA_MAGIC_SET(it, EINA_MAGIC_NONE);
3602 free(it);
3603 }
3604
3605 EAPI Eina_Iterator *
eo_objects_iterator_new(void)3606 eo_objects_iterator_new(void)
3607 {
3608 _Eo_Objects_Iterator *it;
3609 Eo_Id_Table_Data *tdata = _eo_table_data_table_get(_eo_table_data_get(), EFL_ID_DOMAIN_MAIN);
3610
3611 if (!tdata) return NULL;
3612
3613 it = calloc(1, sizeof (*it));
3614 if (!it) return NULL;
3615
3616 it->tdata = tdata;
3617 it->iterator.version = EINA_ITERATOR_VERSION;
3618 it->iterator.next = _eo_objects_iterator_next;
3619 it->iterator.free = _eo_objects_iterator_free;
3620 EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
3621
3622 return (Eina_Iterator *)it;
3623 }
3624
3625 static Eina_Bool
_eo_value_setup(const Eina_Value_Type * type EINA_UNUSED,void * mem)3626 _eo_value_setup(const Eina_Value_Type *type EINA_UNUSED, void *mem)
3627 {
3628 Eo **tmem = mem;
3629 *tmem = NULL;
3630 return EINA_TRUE;
3631 }
3632
3633 static Eina_Bool
_eo_value_flush(const Eina_Value_Type * type EINA_UNUSED,void * mem)3634 _eo_value_flush(const Eina_Value_Type *type EINA_UNUSED, void *mem)
3635 {
3636 Eo **tmem = mem;
3637 if (*tmem)
3638 {
3639 efl_unref(*tmem);
3640 *tmem = NULL;
3641 }
3642 return EINA_TRUE;
3643 }
3644
3645 static Eina_Bool
_eo_value_vset(const Eina_Value_Type * type EINA_UNUSED,void * mem,va_list args)3646 _eo_value_vset(const Eina_Value_Type *type EINA_UNUSED, void *mem, va_list args)
3647 {
3648 Eo **dst = mem;
3649 Eo *src = va_arg(args, Eo *);
3650 efl_replace(dst, src);
3651 return EINA_TRUE;
3652 }
3653
3654 static Eina_Bool
_eo_value_pset(const Eina_Value_Type * type EINA_UNUSED,void * mem,const void * ptr)3655 _eo_value_pset(const Eina_Value_Type *type EINA_UNUSED,
3656 void *mem, const void *ptr)
3657 {
3658 Eo **dst = mem;
3659 Eo * const *src = ptr;
3660 efl_replace(dst, *src);
3661 return EINA_TRUE;
3662 }
3663
3664 static Eina_Bool
_eo_value_pget(const Eina_Value_Type * type EINA_UNUSED,const void * mem,void * ptr)3665 _eo_value_pget(const Eina_Value_Type *type EINA_UNUSED,
3666 const void *mem, void *ptr)
3667 {
3668 Eo * const *src = mem;
3669 Eo **dst = ptr;
3670 *dst = *src;
3671 return EINA_TRUE;
3672 }
3673
3674 static Eina_Bool
_eo_value_convert_to(const Eina_Value_Type * type EINA_UNUSED,const Eina_Value_Type * convert,const void * type_mem,void * convert_mem)3675 _eo_value_convert_to(const Eina_Value_Type *type EINA_UNUSED, const Eina_Value_Type *convert, const void *type_mem, void *convert_mem)
3676 {
3677 Eo * const *eo = type_mem;
3678
3679 if (convert == EINA_VALUE_TYPE_STRINGSHARE ||
3680 convert == EINA_VALUE_TYPE_STRING)
3681 {
3682 const char *other_mem;
3683 char buf[256];
3684 snprintf(buf, sizeof(buf), "Object id: %p, class: %s, name: %s",
3685 *eo, efl_class_name_get(efl_class_get(*eo)),
3686 efl_debug_name_get(*eo));
3687 other_mem = buf;
3688 return eina_value_type_pset(convert, convert_mem, &other_mem);
3689 }
3690 return EINA_FALSE;
3691 }
3692
3693 static Eina_Bool
_eo_value_copy(const Eina_Value_Type * type EINA_UNUSED,const void * mem,void * ptr)3694 _eo_value_copy(const Eina_Value_Type *type EINA_UNUSED, const void *mem, void *ptr)
3695 {
3696 Eo * const *src = mem;
3697 Eo **dst = ptr;
3698
3699 if (!src || !dst) return EINA_FALSE;
3700 *dst = efl_ref(*src);
3701
3702 return EINA_TRUE;
3703 }
3704
3705 static const Eina_Value_Type _EINA_VALUE_TYPE_OBJECT = {
3706 .version = EINA_VALUE_TYPE_VERSION,
3707 .value_size = sizeof(Eo *),
3708 .name = "Efl_Object",
3709 .setup = _eo_value_setup,
3710 .flush = _eo_value_flush,
3711 .copy = _eo_value_copy,
3712 .compare = NULL,
3713 .convert_to = _eo_value_convert_to,
3714 .convert_from = NULL,
3715 .vset = _eo_value_vset,
3716 .pset = _eo_value_pset,
3717 .pget = _eo_value_pget
3718 };
3719
3720 EOAPI const Eina_Value_Type *EINA_VALUE_TYPE_OBJECT = &_EINA_VALUE_TYPE_OBJECT;
3721
3722 static const Efl_Object_Property_Reflection*
_efl_class_reflection_find(const _Efl_Class * klass,const char * property_name)3723 _efl_class_reflection_find(const _Efl_Class *klass, const char *property_name)
3724 {
3725 const _Efl_Class **klass_iter = klass->extensions;
3726 const Efl_Object_Property_Reflection_Ops *ref_ops = klass->reflection;
3727 unsigned int i;
3728
3729 for (i = 0; ref_ops && i < ref_ops->count; ++i)
3730 {
3731 if (eina_streq(property_name, ref_ops->table[i].property_name))
3732 return &ref_ops->table[i];
3733 }
3734
3735 if (klass->parent)
3736 {
3737 const Efl_Object_Property_Reflection *ref;
3738
3739 ref = _efl_class_reflection_find(klass->parent, property_name);
3740 if (ref) return ref;
3741 }
3742
3743 for (; *klass_iter; klass_iter++)
3744 {
3745 const Efl_Object_Property_Reflection *ref;
3746
3747 ref = _efl_class_reflection_find(*klass_iter, property_name);
3748 if (ref) return ref;
3749 }
3750
3751 return NULL;
3752 }
3753
3754 EAPI Eina_Error
efl_property_reflection_set(Eo * obj_id,const char * property_name,Eina_Value value)3755 efl_property_reflection_set(Eo *obj_id, const char *property_name, Eina_Value value)
3756 {
3757 Eina_Error r = EINA_ERROR_NOT_IMPLEMENTED;
3758 Eina_Bool freed = EINA_FALSE;
3759
3760 EO_OBJ_POINTER_GOTO(obj_id, obj, end);
3761 const Efl_Object_Property_Reflection *reflection = _efl_class_reflection_find(obj->klass, property_name);
3762
3763 if (reflection && reflection->set)
3764 {
3765 r = reflection->set(obj_id, value);
3766 freed = EINA_TRUE;
3767 }
3768
3769 end:
3770 if (!freed) eina_value_flush(&value);
3771 EO_OBJ_DONE(obj_id);
3772 return r;
3773 }
3774
3775 EAPI Eina_Value
efl_property_reflection_get(const Eo * obj_id,const char * property_name)3776 efl_property_reflection_get(const Eo *obj_id, const char *property_name)
3777 {
3778 Eina_Value r = eina_value_error_init(EINA_ERROR_NOT_IMPLEMENTED);
3779
3780 EO_OBJ_POINTER_GOTO(obj_id, obj, end);
3781 const Efl_Object_Property_Reflection *reflection = _efl_class_reflection_find(obj->klass, property_name);
3782
3783 if (reflection && reflection->get)
3784 r = reflection->get(obj_id);
3785
3786 end:
3787 EO_OBJ_DONE(obj_id);
3788
3789 return r;
3790 }
3791
3792 EAPI Eina_Bool
efl_property_reflection_exist(Eo * obj_id,const char * property_name)3793 efl_property_reflection_exist(Eo *obj_id, const char *property_name)
3794 {
3795 Eina_Bool r = EINA_FALSE;
3796 EO_OBJ_POINTER_GOTO(obj_id, obj, end);
3797 const Efl_Object_Property_Reflection *reflection = _efl_class_reflection_find(obj->klass, property_name);
3798
3799 if (reflection) r = EINA_TRUE;
3800 end:
3801 EO_OBJ_DONE(obj_id);
3802 return r;
3803 }
3804
3805 EAPI Efl_Class_Type
efl_class_type_get(const Efl_Class * klass_id)3806 efl_class_type_get(const Efl_Class *klass_id)
3807 {
3808 EO_CLASS_POINTER_RETURN_VAL(klass_id, klass, EFL_CLASS_TYPE_INVALID);
3809
3810 return klass->desc->type;
3811 }
3812
3813
3814 EAPI Eina_Bool
efl_ownable_get(const Eo * obj)3815 efl_ownable_get(const Eo *obj)
3816 {
3817 int ref = efl_ref_count(obj);
3818
3819 if (efl_parent_get(obj))
3820 ref --;
3821
3822 if (ref <= 0)
3823 ERR("There is no free reference to pass this object. Please check that this object is really owned by you.");
3824 return (ref > 0);
3825 }
3826