efl/src/lib/eo/eo.c

3826 lines
109 KiB
C
Raw Normal View History

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#if defined HAVE_DLADDR && ! defined _WIN32
# include <dlfcn.h>
#endif
#include <Eina.h>
#ifdef _WIN32
# include <evil_private.h> /* evil_time_get dladdr */
2016-12-03 03:41:09 -08:00
#endif
#if defined(__APPLE__) && defined(__MACH__)
# include <mach/mach_time.h>
#endif
#include "Eo.h"
#include "eo_ptr_indirection.h"
#include "eo_private.h"
#include "eo_add_fallback.h"
#include "eo_internal.h"
#include "efl_object_override.eo.c"
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
#ifdef HAVE_EXECINFO_H
#include <execinfo.h>
#endif
#ifdef HAVE_VALGRIND
# include <valgrind.h>
# include <memcheck.h>
#endif
static Eina_Bool _eo_trash_bypass = EINA_FALSE;
#define EO_CLASS_IDS_FIRST 1
#define EFL_OBJECT_OP_IDS_FIRST 1
/* Used inside the class_get functions of classes, see #EFL_DEFINE_CLASS */
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API Eina_Lock _efl_class_creation_lock;
EO_API unsigned int _efl_object_init_generation = 1;
int _eo_log_dom = -1;
Eina_Thread _efl_object_main_thread;
static unsigned int efl_del_api_generation = 0;
static Efl_Object_Op _efl_del_api_op_id = 0;
static Eina_Hash *class_overrides;
typedef enum _Eo_Ref_Op {
EO_REF_OP_NONE,
EO_REF_OP_NEW,
EO_REF_OP_FREE,
EO_REF_OP_REF,
EO_REF_OP_UNREF,
EO_REF_OP_REUSE,
} Eo_Ref_Op;
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
static inline void _eo_log_obj_init(void);
static inline void _eo_log_obj_shutdown(void);
static inline void _eo_log_obj_ref_op(const _Eo_Object *obj, Eo_Ref_Op ref_op);
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
#ifdef EO_DEBUG
#define EO_LOG_OBJS_BACKTRACE_MAX 1022
#define EO_LOG_OBJS_BACKTRACE_DEFAULT 62
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
static int _eo_log_objs_dom = -1;
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
static Eo_Ref_Op _eo_log_objs_level = EO_REF_OP_NONE;
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
static Eina_Inarray _eo_log_objs_debug;
static Eina_Inarray _eo_log_objs_no_debug;
static double _eo_log_time_start;
static const char *_eo_ref_op_str[] = {
"ERROR",
"New ",
"Free ",
"Ref ",
"Unref",
"Reuse",
};
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
#ifdef HAVE_BACKTRACE
static Eina_Array _eo_log_objs;
static Eina_Spinlock _eo_log_objs_lock;
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
#endif
#else
static inline void _eo_log_obj_init(void) { }
static inline void _eo_log_obj_shutdown(void) { }
static inline void _eo_log_obj_ref_op(const _Eo_Object *obj EINA_UNUSED, Eo_Ref_Op ref_op EINA_UNUSED) { }
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
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) { }
#endif
static _Efl_Class **_eo_classes = NULL;
static Eo_Id _eo_classes_last_id = 0;
static Eo_Id _eo_classes_alloc = 0;
static int _efl_object_init_count = 0;
static Eina_Hash *_ops_storage = NULL;
static Eina_Spinlock _ops_storage_lock;
static const Efl_Object_Optional efl_object_optional_cow_default = {};
Eina_Cow *efl_object_optional_cow = NULL;
2013-04-10 19:58:53 -07:00
static size_t _eo_sz = 0;
2013-06-17 14:33:19 -07:00
static size_t _eo_class_sz = 0;
2013-04-10 19:58:53 -07:00
static void _eo_condtor_reset(_Eo_Object *obj);
static inline void *_efl_data_scope_get(const _Eo_Object *obj, const _Efl_Class *klass);
static inline void *_efl_data_xref_internal(const char *file, int line, _Eo_Object *obj, const _Efl_Class *klass, const _Eo_Object *ref_obj);
static inline void _efl_data_xunref_internal(_Eo_Object *obj, void *data, const _Eo_Object *ref_obj);
static inline Efl_Object_Op _efl_object_api_op_id_get_internal(const void *api_func);
/* Start of Dich */
/* We are substracting the mask here instead of "AND"ing because it's a hot path,
* it should be a valid class at this point, and this lets the compiler do 1
* substraction at compile time. */
#define _UNMASK_ID(id) ((id) - MASK_CLASS_TAG)
#define ID_CLASS_GET(id) ({ \
(_Efl_Class *) (((_UNMASK_ID(id) <= _eo_classes_last_id) && (_UNMASK_ID(id) > 0)) ? \
(_eo_classes[_UNMASK_ID(id) - 1]) : NULL); \
})
#define EFL_OBJECT_OP_CLASS_PART(op) op >> 16
#define EFL_OBJECT_OP_FUNC_PART(op) op & 0xffff
#define EFL_OBJECT_OP_CREATE_OP_ID(class_id, func_id) ((unsigned short)class_id)<<16|((unsigned short)func_id&0xffff)
static const _Efl_Class *
_eo_op_class_get(Efl_Object_Op op)
2016-08-15 09:11:13 -07:00
{
short class_id = EFL_OBJECT_OP_CLASS_PART(op);
return _eo_classes[class_id];
2016-08-15 09:11:13 -07:00
}
#if defined(DEBUG_VTABLE_ALLOCATION)
static int _allocated_memory = 0;
2016-08-15 09:11:13 -07:00
static inline void*
_vtable_alloc(unsigned long n, size_t elem)
{
_allocated_memory += n*elem;
return calloc(n, elem);
}
#else
static inline void*
_vtable_alloc(unsigned long n, size_t elem)
{
return calloc(n, elem);
}
#endif
/**
* This inits the vtable with a given size
*/
static void
_vtable_init_size(Eo_Vtable *vtable, unsigned int size)
{
//we assume here that _eo_classes_last_id was called before
vtable->size = size;
vtable->chain = _vtable_alloc(vtable->size, sizeof(Eo_Vtable_Node));
}
/**
* This inits the vtable wit hthe current size of allocated tables
*/
static void
_vtable_init(Eo_Vtable *vtable)
{
//we assume here that _eo_classes_last_id was called before
_vtable_init_size(vtable, _eo_classes_last_id);
2016-08-15 09:11:13 -07:00
}
/**
* This removes all nodes from the klass that are copied from mro
*/
static void
_vtable_mro_free(const _Efl_Class *klass)
eo: rework vtable allocation scheme Summary: with this commit a new way of allocating vtables arrived. The old mechnism was to allocate a table big enough to carry *all* functions at once, in order to not allocate that much memory for functions that are not implemented on a specific klass, dichchains have been used, which can be seens as a 2D matrix, where columns are only allocated if min 1 entry needs to be written, this may have been a good way to allocate back in the day when all this with eo started, however, it showed to not pay off. With this new way, we allocate a array of arrays. the first lvl array is carrying enough slots, that *all* up to the time defined interfaces/classes/abstracts/mixins can be implemented. The second lvl array then has exactly the size of the defined APIs. The second lvl array is obviously only allocated if needed. When comparing the two methods, i messured two things, the usage based on memory allocation for vtable-way-1 and vtable-way-2. Additionally, i checked the overall memory usage of elementary_test using pmap. The first messurement is a little bit more exact. The second messurement is more biased, but captures the whole picture. Memory allocation tracking: vtable-way-1 - vtable-way-2 = 74680 Byte Pmap memory tracking: vtable-way1 - vtable-way-2 = 217088 Byte The second messurement shows a bigger impact, likely because this is also showing off all the sideeffects that we are taking place due to fewer allocations. Depends on D11524 Reviewers: zmike, tasn, stefan_schmidt, woohyun, cedric, raster Subscribers: #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D11535
2020-03-20 04:32:38 -07:00
{
const _Efl_Class **mro_itr = klass->mro;
const Eo_Vtable *vtable = &klass->vtable;
for ( ; *mro_itr ; mro_itr++)
eo: rework vtable allocation scheme Summary: with this commit a new way of allocating vtables arrived. The old mechnism was to allocate a table big enough to carry *all* functions at once, in order to not allocate that much memory for functions that are not implemented on a specific klass, dichchains have been used, which can be seens as a 2D matrix, where columns are only allocated if min 1 entry needs to be written, this may have been a good way to allocate back in the day when all this with eo started, however, it showed to not pay off. With this new way, we allocate a array of arrays. the first lvl array is carrying enough slots, that *all* up to the time defined interfaces/classes/abstracts/mixins can be implemented. The second lvl array then has exactly the size of the defined APIs. The second lvl array is obviously only allocated if needed. When comparing the two methods, i messured two things, the usage based on memory allocation for vtable-way-1 and vtable-way-2. Additionally, i checked the overall memory usage of elementary_test using pmap. The first messurement is a little bit more exact. The second messurement is more biased, but captures the whole picture. Memory allocation tracking: vtable-way-1 - vtable-way-2 = 74680 Byte Pmap memory tracking: vtable-way1 - vtable-way-2 = 217088 Byte The second messurement shows a bigger impact, likely because this is also showing off all the sideeffects that we are taking place due to fewer allocations. Depends on D11524 Reviewers: zmike, tasn, stefan_schmidt, woohyun, cedric, raster Subscribers: #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D11535
2020-03-20 04:32:38 -07:00
{
const Eo_Vtable *mro_vtable = &(*mro_itr)->vtable;
if ((*mro_itr) == klass)
continue;
for (unsigned int i = 0; i < mro_vtable->size; ++i)
{
if (i == klass->class_id)
continue;
if (vtable->chain[i].funcs && mro_vtable->chain[i].funcs == vtable->chain[i].funcs)
{
vtable->chain[i].funcs = NULL;
}
}
}
}
static void
_vtable_free(Eo_Vtable *vtable, const Eo_Vtable *root)
{
if (root)
{
EINA_SAFETY_ON_FALSE_RETURN(vtable->size == root->size);
2016-08-15 09:11:13 -07:00
}
for (int i = 0; i < vtable->size; ++i)
2016-08-15 09:11:13 -07:00
{
if (root && root->chain[i].funcs == vtable->chain[i].funcs)
vtable->chain[i].count = 0;
if (vtable->chain[i].count)
2016-08-15 09:11:13 -07:00
{
free(vtable->chain[i].funcs);
2016-08-15 09:11:13 -07:00
}
}
free(vtable->chain);
2016-08-15 09:11:13 -07:00
}
/**
* This takes over all set chains of the src to dest.
* This should only be called on Eo_Vtables, which are initialized with this value.
* Previous setted values are going to be overwritten.
*/
static void
_vtable_take_over(Eo_Vtable *dest, const Eo_Vtable *src)
2016-08-15 09:11:13 -07:00
{
for (int i = 0; i < src->size; ++i)
2016-08-15 09:11:13 -07:00
{
if (src->chain[i].funcs)
{
dest->chain[i] = src->chain[i];
}
2016-08-15 09:11:13 -07:00
}
}
2016-08-15 09:11:13 -07:00
/**
* Fills the node of the passed class id with a empty none NULL pointer.
* This is used to indicate that a specific node has a normal 0 size, but is set.
*/
static void
_vtable_insert_empty_funcs(Eo_Vtable *vtable, unsigned short class_id)
{
vtable->chain[class_id].funcs = (void*)0x1010101;
vtable->chain[class_id].count = 0;
}
2016-08-15 09:11:13 -07:00
/**
* duplicate the source node, and write the duplicated values to the destination
* No logical changes are applied to src.
*/
static void
_vtable_copy_node(Eo_Vtable_Node *dest, const Eo_Vtable_Node *src)
{
dest->count = src->count;
dest->funcs = _vtable_alloc(sizeof(op_type_funcs), src->count);
memcpy(dest->funcs, src->funcs, sizeof(op_type_funcs) * src->count);
}
2016-08-15 09:11:13 -07:00
/**
* Initialize a node with a empty funcs array of the passed length
*/
static void
_vtable_prepare_empty_node(Eo_Vtable *dest, unsigned int length, unsigned int class_id)
{
dest->chain[class_id].count = length;
dest->chain[class_id].funcs = _vtable_alloc(sizeof(op_type_funcs), dest->chain[class_id].count);
2016-08-15 09:11:13 -07:00
}
/**
* Copy all setted APIs from src to dest.
* Already set function slots are going to be replaced.
*/
static void
_vtable_merge_defined_api(Eo_Vtable *dest, const Eo_Vtable *src, Eina_Bool *hitmap)
2016-08-15 09:11:13 -07:00
{
for (unsigned int i = 0; i < src->size; ++i)
2016-08-15 09:11:13 -07:00
{
//if there is a source node evalulate if we need to copy it
if (src->chain[i].funcs)
{
if (!dest->chain[i].funcs)
{
dest->chain[i] = src->chain[i];
EINA_SAFETY_ON_FALSE_RETURN(hitmap[i] == EINA_FALSE);
}
else
{
if (!hitmap[i])
{
const Eo_Vtable_Node node = dest->chain[i];
if (!node.count)
_vtable_insert_empty_funcs(dest, i);
else
_vtable_copy_node(&dest->chain[i], &node); //we copy what we have, and overwrite in the later for loop
hitmap[i] = EINA_TRUE;
}
for (int j = 0; j < src->chain[i].count; ++j)
{
if (src->chain[i].funcs[j].func)
dest->chain[i].funcs[j] = src->chain[i].funcs[j];
}
}
}
}
}
/**
* Ensure that all set nodes from src are also set on dest.
* No real values are copied, the newly taken or allocated slots will be empty.
*/
static void
_vtable_merge_empty(Eo_Vtable *dest, const Eo_Vtable *src, Eina_Bool *hitmap)
{
for (unsigned int i = 0; i < src->size; ++i)
{
if (src->chain[i].funcs && !dest->chain[i].funcs)
{
if (!src->chain[i].count)
{
dest->chain[i].funcs = src->chain[i].funcs;
dest->chain[i].count = src->chain[i].count;
}
else
{
_vtable_prepare_empty_node(dest, src->chain[i].count, i);
hitmap[i] = EINA_TRUE;
}
}
}
}
static inline const op_type_funcs *
_vtable_func_get(const Eo_Vtable *vtable, Efl_Object_Op op)
{
unsigned short class_id = EFL_OBJECT_OP_CLASS_PART(op);
unsigned short func_id = EFL_OBJECT_OP_FUNC_PART(op);
if (EINA_UNLIKELY(vtable->size <= class_id))
return NULL;
if (EINA_UNLIKELY(vtable->chain[class_id].count <= func_id))
return NULL;
return &vtable->chain[class_id].funcs[func_id];
}
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)
{
2014-01-03 07:02:00 -08:00
op_type_funcs *fsrc;
unsigned short class_id = EFL_OBJECT_OP_CLASS_PART(op);
unsigned short func_id = EFL_OBJECT_OP_FUNC_PART(op);
Eo_Vtable_Node *hirachy_node = NULL;
Eo_Vtable_Node *node = NULL;
eo: rework vtable allocation scheme Summary: with this commit a new way of allocating vtables arrived. The old mechnism was to allocate a table big enough to carry *all* functions at once, in order to not allocate that much memory for functions that are not implemented on a specific klass, dichchains have been used, which can be seens as a 2D matrix, where columns are only allocated if min 1 entry needs to be written, this may have been a good way to allocate back in the day when all this with eo started, however, it showed to not pay off. With this new way, we allocate a array of arrays. the first lvl array is carrying enough slots, that *all* up to the time defined interfaces/classes/abstracts/mixins can be implemented. The second lvl array then has exactly the size of the defined APIs. The second lvl array is obviously only allocated if needed. When comparing the two methods, i messured two things, the usage based on memory allocation for vtable-way-1 and vtable-way-2. Additionally, i checked the overall memory usage of elementary_test using pmap. The first messurement is a little bit more exact. The second messurement is more biased, but captures the whole picture. Memory allocation tracking: vtable-way-1 - vtable-way-2 = 74680 Byte Pmap memory tracking: vtable-way1 - vtable-way-2 = 217088 Byte The second messurement shows a bigger impact, likely because this is also showing off all the sideeffects that we are taking place due to fewer allocations. Depends on D11524 Reviewers: zmike, tasn, stefan_schmidt, woohyun, cedric, raster Subscribers: #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D11535
2020-03-20 04:32:38 -07:00
EINA_SAFETY_ON_FALSE_RETURN_VAL(vtable->size >= class_id, EINA_FALSE);
if (klass->parent && klass->parent->vtable.size > class_id)
hirachy_node = &klass->parent->vtable.chain[class_id];
if (hierarchy_klass)
hirachy_node = &hierarchy_klass->vtable.chain[class_id];
node = &vtable->chain[class_id];
EINA_SAFETY_ON_NULL_RETURN_VAL(node->funcs, EINA_FALSE);
EINA_SAFETY_ON_FALSE_RETURN_VAL(node->count >= func_id, EINA_FALSE);
fsrc = &node->funcs[func_id];
if (hierarchy_klass && !func)
{
if (!func)
{
op_type_funcs funcs = hirachy_node->funcs[func_id];
klass = funcs.src;
func = funcs.func;
}
}
else
{
if (!allow_same_override && (fsrc->src == klass))
{
const _Efl_Class *op_kls = _eo_op_class_get(op);
ERR("Class '%s': Overriding already set func %p for op %d (%s) with %p.",
klass->desc->name, fsrc->func, op, op_kls->desc->name, func);
return EINA_FALSE;
}
}
fsrc->src = klass;
fsrc->func = func;
return EINA_TRUE;
}
/* END OF DICH */
#define _EO_ID_GET(Id) ((Eo_Id) (Id))
static inline Eina_Bool
_eo_is_a_obj(const Eo *eo_id)
{
Eo_Id oid = (Eo_Id) _EO_ID_GET(eo_id);
return !!(oid & MASK_OBJ_TAG);
}
static inline Eina_Bool
_eo_is_a_class(const Eo *eo_id)
{
Eo_Id oid = (Eo_Id) _EO_ID_GET(eo_id);
return !!(oid & MASK_CLASS_TAG);
}
static inline _Efl_Class *
_eo_class_pointer_get(const Efl_Class *klass_id)
{
return ID_CLASS_GET((Eo_Id)klass_id);
}
static const char *
_eo_op_desc_name_get(const Efl_Op_Description *desc)
{
static const char *fct_name = "unknown";
if (!desc)
{
return fct_name;
}
#ifndef _WIN32
# ifdef HAVE_DLADDR
static Dl_info info;
if (dladdr(desc->api_func, &info) != 0)
fct_name = info.dli_sname;
# endif
#else
fct_name = desc->api_func; /* Same on windows */
#endif
return fct_name;
}
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)
{
const _Efl_Class **kls_itr = NULL;
/* Find the kls itr. */
kls_itr = orig_kls->mro;
while (*kls_itr && (*kls_itr != cur_klass))
kls_itr++;
if (*kls_itr)
{
if (super) kls_itr++;
while (*kls_itr)
{
const op_type_funcs *fsrc = _vtable_func_get(&(*kls_itr)->vtable, op);
if (!fsrc || !fsrc->func)
{
kls_itr++;
continue;
}
return fsrc;
}
}
return NULL;
}
static inline void
_apply_auto_unref(_Eo_Object *obj, const Eo *eo_obj)
{
if (EINA_UNLIKELY(obj && obj->auto_unref))
{
if (obj->finalized && !(--obj->auto_unref))
efl_unref(eo_obj);
}
}
2014-04-02 01:46:34 -07:00
/************************************ EO ************************************/
2013-07-18 00:10:07 -07:00
static EFL_FUNC_TLS _Efl_Class *_super_klass = NULL;
static Eo *
_efl_super_cast(const Eo *eo_id, const Efl_Class *cur_klass, Eina_Bool super)
{
EO_CLASS_POINTER_GOTO(cur_klass, super_klass, err);
#ifdef EO_DEBUG
if (EINA_UNLIKELY(!_eo_is_a_obj(eo_id) && !_eo_is_a_class(eo_id))) goto err_obj;
#endif
if (EINA_UNLIKELY(!_eo_is_a_obj(eo_id)))
goto do_klass;
#ifndef EO_DEBUG
if (!super && EINA_UNLIKELY(!efl_isa(eo_id, cur_klass)))
#else
if (EINA_UNLIKELY(!efl_isa(eo_id, cur_klass)))
#endif
goto err_obj_hierarchy;
EO_OBJ_POINTER_RETURN_VAL(eo_id, obj, NULL);
obj->cur_klass = super_klass;
obj->super = super;
EO_OBJ_DONE(eo_id);
return (Eo *) eo_id;
do_klass:
// efl_super(Class) is extremely rarely used, so TLS write is fine
EINA_SAFETY_ON_FALSE_RETURN_VAL(super, NULL);
_super_klass = super_klass;
return (Eo *) eo_id;
err:
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
_EO_POINTER_ERR(cur_klass, "Class (%p) is an invalid ref.", cur_klass);
return NULL;
#ifdef EO_DEBUG
err_obj:
_EO_POINTER_ERR(eo_id, "Object (%p) is an invalid ref, class=%p (%s).", eo_id, cur_klass, efl_class_name_get(cur_klass));
return NULL;
#endif
err_obj_hierarchy:
_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));
return NULL;
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API Eo *
efl_super(const Eo *eo_id, const Efl_Class *cur_klass)
{
return _efl_super_cast(eo_id, cur_klass, EINA_TRUE);
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API Eo *
efl_cast(const Eo *eo_id, const Efl_Class *cur_klass)
{
return _efl_super_cast(eo_id, cur_klass, EINA_FALSE);
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API Eina_Bool
eina: remove usless newline Summary: ecore_evas: remove debug eina: unregister log level when done with Fixes a constant memory leak. eina: introduce EINA_HOT and EINA_COLD These attributes respectivelly expand to __attribute__ ((hot)) and __attribute__ ((cold)) when available. They allow to mark functions are being hot/cold (frequently used or not) as well as to qualify labels within a function (likely/unlikely branches). eo: speed-up generated calls by removing call cache The call cache needed to by thread-local, to avoid concurrency issues. Problem with TLS is that is adds an extra overhead, which appears to be greater than the optimization the cache provides. Op is naturally atomic, because it is an unsigned integer. As such, it cannot be tempered with while another thread is reading it. When entering the generated function, the first operation done is reading 'op'. If we have concurrency, we will have access sequences returning either EFL_NOOP or a VALID op, because 'op' is not set until the very end of the function, when everything has been computed. As such, we now use the 'op' atomic integer to instore a lock-free/wait-free mechanism, which allows to drop the TLS nature of the cache, speeding up the access to the cache, and therefore making functions execute faster. We don't test anymore the generation count. This can be put as a limitation. If means that if you call efl_object_shutdown() and re-initialize it later with different data, opcodes will be invalid. I am not sure there is any usecase for this to ever happen. We could move all the caches in a dedicated section, that can be overwritten after a call to efl_object_shutdown(), but I am not sure it will be very portable. Benchmark: mean over 3 executions of ELM_TEST_AUTOBOUNCE=100 time elementary_test -to genlist ``` BEFORE AFTER ------------------------------------------------------------ time (ns) 11114111647.0 9147676220.0 frames 2872.3333333333335 2904.6666666666665 time per frame (ns) 3869364.6666666665 3149535.3333333335 user time (s) 11.096666666666666 9.22 cpu (%) 22.666666666666668 18.333333333333332 ``` Ref T6580 Reviewers: raster, cedric Subscribers: cedric, jpeg Maniphest Tasks: T6580 Differential Revision: https://phab.enlightenment.org/D5738
2018-01-15 21:58:38 -08:00
_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)
{
eina: remove usless newline Summary: ecore_evas: remove debug eina: unregister log level when done with Fixes a constant memory leak. eina: introduce EINA_HOT and EINA_COLD These attributes respectivelly expand to __attribute__ ((hot)) and __attribute__ ((cold)) when available. They allow to mark functions are being hot/cold (frequently used or not) as well as to qualify labels within a function (likely/unlikely branches). eo: speed-up generated calls by removing call cache The call cache needed to by thread-local, to avoid concurrency issues. Problem with TLS is that is adds an extra overhead, which appears to be greater than the optimization the cache provides. Op is naturally atomic, because it is an unsigned integer. As such, it cannot be tempered with while another thread is reading it. When entering the generated function, the first operation done is reading 'op'. If we have concurrency, we will have access sequences returning either EFL_NOOP or a VALID op, because 'op' is not set until the very end of the function, when everything has been computed. As such, we now use the 'op' atomic integer to instore a lock-free/wait-free mechanism, which allows to drop the TLS nature of the cache, speeding up the access to the cache, and therefore making functions execute faster. We don't test anymore the generation count. This can be put as a limitation. If means that if you call efl_object_shutdown() and re-initialize it later with different data, opcodes will be invalid. I am not sure there is any usecase for this to ever happen. We could move all the caches in a dedicated section, that can be overwritten after a call to efl_object_shutdown(), but I am not sure it will be very portable. Benchmark: mean over 3 executions of ELM_TEST_AUTOBOUNCE=100 time elementary_test -to genlist ``` BEFORE AFTER ------------------------------------------------------------ time (ns) 11114111647.0 9147676220.0 frames 2872.3333333333335 2904.6666666666665 time per frame (ns) 3869364.6666666665 3149535.3333333335 user time (s) 11.096666666666666 9.22 cpu (%) 22.666666666666668 18.333333333333332 ``` Ref T6580 Reviewers: raster, cedric Subscribers: cedric, jpeg Maniphest Tasks: T6580 Differential Revision: https://phab.enlightenment.org/D5738
2018-01-15 21:58:38 -08:00
const _Efl_Class *klass, *main_klass;
const _Efl_Class *cur_klass = NULL;
_Eo_Object *obj = NULL;
const Eo_Vtable *vtable = NULL;
const op_type_funcs *func;
Eina_Bool super = EINA_TRUE;
if (EINA_UNLIKELY(!eo_id)) goto on_null;
2013-12-30 06:24:15 -08:00
EO_OBJ_POINTER_RETURN_VAL_PROXY(eo_id, _obj, EINA_FALSE);
obj = _obj;
klass = _obj->klass;
vtable = EO_VTABLE2(obj);
if (EINA_UNLIKELY(_obj->cur_klass != NULL))
{
// YES this is a goto with a label to return. this is a
// micro-optimization to move infrequent code out of the
// hot path of the function
goto obj_super;
}
obj_super_back:
_efl_ref(_obj);
eina: remove usless newline Summary: ecore_evas: remove debug eina: unregister log level when done with Fixes a constant memory leak. eina: introduce EINA_HOT and EINA_COLD These attributes respectivelly expand to __attribute__ ((hot)) and __attribute__ ((cold)) when available. They allow to mark functions are being hot/cold (frequently used or not) as well as to qualify labels within a function (likely/unlikely branches). eo: speed-up generated calls by removing call cache The call cache needed to by thread-local, to avoid concurrency issues. Problem with TLS is that is adds an extra overhead, which appears to be greater than the optimization the cache provides. Op is naturally atomic, because it is an unsigned integer. As such, it cannot be tempered with while another thread is reading it. When entering the generated function, the first operation done is reading 'op'. If we have concurrency, we will have access sequences returning either EFL_NOOP or a VALID op, because 'op' is not set until the very end of the function, when everything has been computed. As such, we now use the 'op' atomic integer to instore a lock-free/wait-free mechanism, which allows to drop the TLS nature of the cache, speeding up the access to the cache, and therefore making functions execute faster. We don't test anymore the generation count. This can be put as a limitation. If means that if you call efl_object_shutdown() and re-initialize it later with different data, opcodes will be invalid. I am not sure there is any usecase for this to ever happen. We could move all the caches in a dedicated section, that can be overwritten after a call to efl_object_shutdown(), but I am not sure it will be very portable. Benchmark: mean over 3 executions of ELM_TEST_AUTOBOUNCE=100 time elementary_test -to genlist ``` BEFORE AFTER ------------------------------------------------------------ time (ns) 11114111647.0 9147676220.0 frames 2872.3333333333335 2904.6666666666665 time per frame (ns) 3869364.6666666665 3149535.3333333335 user time (s) 11.096666666666666 9.22 cpu (%) 22.666666666666668 18.333333333333332 ``` Ref T6580 Reviewers: raster, cedric Subscribers: cedric, jpeg Maniphest Tasks: T6580 Differential Revision: https://phab.enlightenment.org/D5738
2018-01-15 21:58:38 -08:00
main_klass = klass;
/* If we have a current class, we need to itr to the next. */
if (cur_klass)
{
// YES this is a goto with a label to return. this is a
// micro-optimization to move infrequent code out of the
// hot path of the function
goto ok_cur_klass;
}
else
{
eina: remove usless newline Summary: ecore_evas: remove debug eina: unregister log level when done with Fixes a constant memory leak. eina: introduce EINA_HOT and EINA_COLD These attributes respectivelly expand to __attribute__ ((hot)) and __attribute__ ((cold)) when available. They allow to mark functions are being hot/cold (frequently used or not) as well as to qualify labels within a function (likely/unlikely branches). eo: speed-up generated calls by removing call cache The call cache needed to by thread-local, to avoid concurrency issues. Problem with TLS is that is adds an extra overhead, which appears to be greater than the optimization the cache provides. Op is naturally atomic, because it is an unsigned integer. As such, it cannot be tempered with while another thread is reading it. When entering the generated function, the first operation done is reading 'op'. If we have concurrency, we will have access sequences returning either EFL_NOOP or a VALID op, because 'op' is not set until the very end of the function, when everything has been computed. As such, we now use the 'op' atomic integer to instore a lock-free/wait-free mechanism, which allows to drop the TLS nature of the cache, speeding up the access to the cache, and therefore making functions execute faster. We don't test anymore the generation count. This can be put as a limitation. If means that if you call efl_object_shutdown() and re-initialize it later with different data, opcodes will be invalid. I am not sure there is any usecase for this to ever happen. We could move all the caches in a dedicated section, that can be overwritten after a call to efl_object_shutdown(), but I am not sure it will be very portable. Benchmark: mean over 3 executions of ELM_TEST_AUTOBOUNCE=100 time elementary_test -to genlist ``` BEFORE AFTER ------------------------------------------------------------ time (ns) 11114111647.0 9147676220.0 frames 2872.3333333333335 2904.6666666666665 time per frame (ns) 3869364.6666666665 3149535.3333333335 user time (s) 11.096666666666666 9.22 cpu (%) 22.666666666666668 18.333333333333332 ``` Ref T6580 Reviewers: raster, cedric Subscribers: cedric, jpeg Maniphest Tasks: T6580 Differential Revision: https://phab.enlightenment.org/D5738
2018-01-15 21:58:38 -08:00
func = _vtable_func_get(vtable, op);
EINA_PREFETCH_NOCACHE(func);
// this is not very likely to happen - but may if its an invalid
// call or a composite object, but either way, it's not very likely
// so make it a goto to save on instruction cache
if (!func) goto end;
}
ok_cur_klass_back:
2013-11-08 07:30:25 -08:00
if (EINA_LIKELY(func->func && func->src))
2013-07-08 08:31:36 -07:00
{
call->eo_id = eo_id;
call->obj = obj;
call->func = func->func;
call->data = _efl_data_scope_get(obj, func->src);
return EINA_TRUE;
2013-07-08 08:31:36 -07:00
}
// very unlikely in general to use a goto to move code out of l1 cache
// ie instruction cache
if (func->src != NULL) goto err_func_src;
end:
2013-07-08 08:31:36 -07:00
/* Try composite objects */
{
Eina_List *itr;
Eo *emb_obj_id;
EINA_LIST_FOREACH(obj->opt->composite_objects, itr, emb_obj_id)
{
EO_OBJ_POINTER_PROXY(emb_obj_id, emb_obj);
if (EINA_UNLIKELY(!emb_obj)) continue;
func = _vtable_func_get(&emb_obj->klass->vtable, op);
if (func == NULL) goto composite_continue;
if (EINA_LIKELY(func->func && func->src))
{
call->eo_id = _eo_obj_id_get(emb_obj);
call->obj = _efl_ref(emb_obj);
call->func = func->func;
call->data = _efl_data_scope_get(emb_obj, func->src);
/* We reffed it above, but no longer need/use it. */
_efl_unref(obj);
EO_OBJ_DONE(emb_obj_id);
return EINA_TRUE;
}
composite_continue:
EO_OBJ_DONE(emb_obj_id);
}
}
// all of this is error handling at the end so... rare-ish
// If it's a do_super call.
if (cur_klass)
{
ERR("in %s:%d: func '%s' (%d) could not be resolved on %s for class '%s' for super of '%s'.",
file, line, func_name, op, efl_debug_name_get(eo_id), main_klass->desc->name,
cur_klass->desc->name);
goto err;
}
else
{
/* we should not be able to take this branch */
ERR("in %s:%d: func '%s' (%d) could not be resolved on %s for class '%s'.",
file, line, func_name, op, efl_debug_name_get(eo_id), main_klass->desc->name);
goto err;
}
2018-01-16 01:32:15 -08:00
err_func_src:
ERR("in %s:%d: you called a pure virtual func '%s' (%d) of class '%s'.",
eina: remove usless newline Summary: ecore_evas: remove debug eina: unregister log level when done with Fixes a constant memory leak. eina: introduce EINA_HOT and EINA_COLD These attributes respectivelly expand to __attribute__ ((hot)) and __attribute__ ((cold)) when available. They allow to mark functions are being hot/cold (frequently used or not) as well as to qualify labels within a function (likely/unlikely branches). eo: speed-up generated calls by removing call cache The call cache needed to by thread-local, to avoid concurrency issues. Problem with TLS is that is adds an extra overhead, which appears to be greater than the optimization the cache provides. Op is naturally atomic, because it is an unsigned integer. As such, it cannot be tempered with while another thread is reading it. When entering the generated function, the first operation done is reading 'op'. If we have concurrency, we will have access sequences returning either EFL_NOOP or a VALID op, because 'op' is not set until the very end of the function, when everything has been computed. As such, we now use the 'op' atomic integer to instore a lock-free/wait-free mechanism, which allows to drop the TLS nature of the cache, speeding up the access to the cache, and therefore making functions execute faster. We don't test anymore the generation count. This can be put as a limitation. If means that if you call efl_object_shutdown() and re-initialize it later with different data, opcodes will be invalid. I am not sure there is any usecase for this to ever happen. We could move all the caches in a dedicated section, that can be overwritten after a call to efl_object_shutdown(), but I am not sure it will be very portable. Benchmark: mean over 3 executions of ELM_TEST_AUTOBOUNCE=100 time elementary_test -to genlist ``` BEFORE AFTER ------------------------------------------------------------ time (ns) 11114111647.0 9147676220.0 frames 2872.3333333333335 2904.6666666666665 time per frame (ns) 3869364.6666666665 3149535.3333333335 user time (s) 11.096666666666666 9.22 cpu (%) 22.666666666666668 18.333333333333332 ``` Ref T6580 Reviewers: raster, cedric Subscribers: cedric, jpeg Maniphest Tasks: T6580 Differential Revision: https://phab.enlightenment.org/D5738
2018-01-15 21:58:38 -08:00
file, line, func_name, op, klass->desc->name);
err:
_apply_auto_unref(obj, eo_id);
_efl_unref(obj);
_eo_obj_pointer_done((Eo_Id)eo_id);
return EINA_FALSE;
// yes - special "move out of hot path" code blobs with goto's for
// speed reasons to have intr prefetches work better and miss less
ok_cur_klass:
eina: remove usless newline Summary: ecore_evas: remove debug eina: unregister log level when done with Fixes a constant memory leak. eina: introduce EINA_HOT and EINA_COLD These attributes respectivelly expand to __attribute__ ((hot)) and __attribute__ ((cold)) when available. They allow to mark functions are being hot/cold (frequently used or not) as well as to qualify labels within a function (likely/unlikely branches). eo: speed-up generated calls by removing call cache The call cache needed to by thread-local, to avoid concurrency issues. Problem with TLS is that is adds an extra overhead, which appears to be greater than the optimization the cache provides. Op is naturally atomic, because it is an unsigned integer. As such, it cannot be tempered with while another thread is reading it. When entering the generated function, the first operation done is reading 'op'. If we have concurrency, we will have access sequences returning either EFL_NOOP or a VALID op, because 'op' is not set until the very end of the function, when everything has been computed. As such, we now use the 'op' atomic integer to instore a lock-free/wait-free mechanism, which allows to drop the TLS nature of the cache, speeding up the access to the cache, and therefore making functions execute faster. We don't test anymore the generation count. This can be put as a limitation. If means that if you call efl_object_shutdown() and re-initialize it later with different data, opcodes will be invalid. I am not sure there is any usecase for this to ever happen. We could move all the caches in a dedicated section, that can be overwritten after a call to efl_object_shutdown(), but I am not sure it will be very portable. Benchmark: mean over 3 executions of ELM_TEST_AUTOBOUNCE=100 time elementary_test -to genlist ``` BEFORE AFTER ------------------------------------------------------------ time (ns) 11114111647.0 9147676220.0 frames 2872.3333333333335 2904.6666666666665 time per frame (ns) 3869364.6666666665 3149535.3333333335 user time (s) 11.096666666666666 9.22 cpu (%) 22.666666666666668 18.333333333333332 ``` Ref T6580 Reviewers: raster, cedric Subscribers: cedric, jpeg Maniphest Tasks: T6580 Differential Revision: https://phab.enlightenment.org/D5738
2018-01-15 21:58:38 -08:00
func = _eo_kls_itr_next(klass, cur_klass, op, super);
if (!func) goto end;
klass = func->src;
goto ok_cur_klass_back;
obj_super:
{
cur_klass = obj->cur_klass;
super = obj->super;
obj->cur_klass = NULL;
if (_obj_is_override(obj) && cur_klass && super &&
(_eo_class_id_get(cur_klass) == EFL_OBJECT_OVERRIDE_CLASS))
{
/* Doing a efl_super(obj, EFL_OBJECT_OVERRIDE_CLASS) should
* result in calling as if it's a normal class. */
vtable = &klass->vtable;
cur_klass = NULL;
}
}
goto obj_super_back;
on_null:
if (EINA_UNLIKELY(efl_del_api_generation != _efl_object_init_generation))
{
_efl_del_api_op_id = _efl_object_api_op_id_get_internal(EFL_FUNC_COMMON_OP_FUNC(efl_del));
efl_del_api_generation = _efl_object_init_generation;
}
if (op != _efl_del_api_op_id)
WRN("NULL passed to function %s().", func_name);
return EINA_FALSE;
2013-07-08 08:31:36 -07:00
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API void
_efl_object_call_end(Efl_Object_Op_Call_Data *call)
{
if (EINA_LIKELY(!!call->obj))
{
_apply_auto_unref(call->obj, call->eo_id);
_efl_unref(call->obj);
_eo_obj_pointer_done((Eo_Id)call->eo_id);
}
}
static inline Eina_Bool
_eo_api_func_equal(const void *api_func1, const void *api_func2)
{
#ifndef _WIN32
return (api_func1 == api_func2);
#else
/* On Windows, DLL API's will be exported using the dllexport flag.
* When used by another library or executable, they will be declared
* using the dllimport flag. What happens really is that two symbols are
* created, at two different addresses. So it's impossible to match
* them. We fallback to plain string comparison based on the
* function name itself. Slow, but this should rarely happen.
*/
return (api_func2 && api_func1 && !strcmp(api_func2, api_func1));
#endif
}
static inline Efl_Object_Op
_efl_object_api_op_id_get_internal(const void *api_func)
{
eina_spinlock_take(&_ops_storage_lock);
#ifndef _WIN32
Efl_Object_Op op = (uintptr_t) eina_hash_find(_ops_storage, &api_func);
#else
Efl_Object_Op op = (uintptr_t) eina_hash_find(_ops_storage, api_func);
#endif
eina_spinlock_release(&_ops_storage_lock);
return op;
}
/* LEGACY, should be removed before next release */
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API Efl_Object_Op
_efl_object_api_op_id_get(const void *api_func)
{
Efl_Object_Op op = _efl_object_api_op_id_get_internal(api_func);
if (op == EFL_NOOP)
{
ERR("Unable to resolve op for api func %p", api_func);
}
return op;
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API Efl_Object_Op
eo: Add beta API for auto_unref after a call Before screaming in horror (C++...) here's why we may need this: Efl.Part.part API returns an object that is by definition valid for a single function call only. Enforcing this in practice is actually quite hard as all implementation functions must manually take care of the life-cycle. This is a lot of code in many places and a lot of opportunities to forget to properly handle that life-cycle. Also, this means any invalid function call on a part will leak an object. This API absolutely must remain either "internal" or "beta" and definitely not become abused by applications. On top of that such an API can cause great trouble for bindings like C++. As a consequence, only specially crafted APIs like efl_part() should return an object marked as auto_unref. Alternatively this API could be defined in Eo.h or some other Eo_Internal.h. I placed it in efl_object.eo because it's much more convenient :) (read: I'm lazy) **** Performance notes: Tested with clang & gcc (with -O2), I had a look at the output of perf top, in particular the asm view. I used eo_bench in a loop. My conclusions are: - EINA_LIKELY/UNLIKELY actually works. The jump statement varies according to the expectation. I highly doubt all those ugly goto in eo.c / Eo.h are even useful. - The impact of auto_unref on a call_resolve is so small it doesn't even appear in the trace. It is significant inside call_end, though (obviously, that function is just a few lines long). That function accounts for ~1% to ~4% of all CPU time. The impact of auto_unref in call_end is ~4% of the function time. This means ~0.16% of all CPU time (worst measured case). _efl_object_op_api_id_get simply doesn't show up because of caching, so the extra check there is negligible. PS: I also tested EINA_LIKELY/UNLIKELY by compiling with -O2 and looking at the output with objdump. The flag is well respected, and the jump instructions are what you would expect (no jump for LIKELY and jump for UNLIKELY). Conclusion: The goto's in eo.c only make the code harder to read...
2017-10-13 01:18:41 -07:00
_efl_object_op_api_id_get(const void *api_func, const Eo *eo_obj, const char *api_func_name, const char *file, int line)
{
Efl_Object_Op op;
#ifndef EO_DEBUG
eo: Add beta API for auto_unref after a call Before screaming in horror (C++...) here's why we may need this: Efl.Part.part API returns an object that is by definition valid for a single function call only. Enforcing this in practice is actually quite hard as all implementation functions must manually take care of the life-cycle. This is a lot of code in many places and a lot of opportunities to forget to properly handle that life-cycle. Also, this means any invalid function call on a part will leak an object. This API absolutely must remain either "internal" or "beta" and definitely not become abused by applications. On top of that such an API can cause great trouble for bindings like C++. As a consequence, only specially crafted APIs like efl_part() should return an object marked as auto_unref. Alternatively this API could be defined in Eo.h or some other Eo_Internal.h. I placed it in efl_object.eo because it's much more convenient :) (read: I'm lazy) **** Performance notes: Tested with clang & gcc (with -O2), I had a look at the output of perf top, in particular the asm view. I used eo_bench in a loop. My conclusions are: - EINA_LIKELY/UNLIKELY actually works. The jump statement varies according to the expectation. I highly doubt all those ugly goto in eo.c / Eo.h are even useful. - The impact of auto_unref on a call_resolve is so small it doesn't even appear in the trace. It is significant inside call_end, though (obviously, that function is just a few lines long). That function accounts for ~1% to ~4% of all CPU time. The impact of auto_unref in call_end is ~4% of the function time. This means ~0.16% of all CPU time (worst measured case). _efl_object_op_api_id_get simply doesn't show up because of caching, so the extra check there is negligible. PS: I also tested EINA_LIKELY/UNLIKELY by compiling with -O2 and looking at the output with objdump. The flag is well respected, and the jump instructions are what you would expect (no jump for LIKELY and jump for UNLIKELY). Conclusion: The goto's in eo.c only make the code harder to read...
2017-10-13 01:18:41 -07:00
if (!eo_obj) return EFL_NOOP;
#endif
op = _efl_object_api_op_id_get_internal(api_func);
if (op == EFL_NOOP)
{
eo: Add beta API for auto_unref after a call Before screaming in horror (C++...) here's why we may need this: Efl.Part.part API returns an object that is by definition valid for a single function call only. Enforcing this in practice is actually quite hard as all implementation functions must manually take care of the life-cycle. This is a lot of code in many places and a lot of opportunities to forget to properly handle that life-cycle. Also, this means any invalid function call on a part will leak an object. This API absolutely must remain either "internal" or "beta" and definitely not become abused by applications. On top of that such an API can cause great trouble for bindings like C++. As a consequence, only specially crafted APIs like efl_part() should return an object marked as auto_unref. Alternatively this API could be defined in Eo.h or some other Eo_Internal.h. I placed it in efl_object.eo because it's much more convenient :) (read: I'm lazy) **** Performance notes: Tested with clang & gcc (with -O2), I had a look at the output of perf top, in particular the asm view. I used eo_bench in a loop. My conclusions are: - EINA_LIKELY/UNLIKELY actually works. The jump statement varies according to the expectation. I highly doubt all those ugly goto in eo.c / Eo.h are even useful. - The impact of auto_unref on a call_resolve is so small it doesn't even appear in the trace. It is significant inside call_end, though (obviously, that function is just a few lines long). That function accounts for ~1% to ~4% of all CPU time. The impact of auto_unref in call_end is ~4% of the function time. This means ~0.16% of all CPU time (worst measured case). _efl_object_op_api_id_get simply doesn't show up because of caching, so the extra check there is negligible. PS: I also tested EINA_LIKELY/UNLIKELY by compiling with -O2 and looking at the output with objdump. The flag is well respected, and the jump instructions are what you would expect (no jump for LIKELY and jump for UNLIKELY). Conclusion: The goto's in eo.c only make the code harder to read...
2017-10-13 01:18:41 -07:00
EO_OBJ_POINTER(eo_obj, obj);
eina_log_print(_eo_log_dom, EINA_LOG_LEVEL_ERR,
file, api_func_name, line,
"Unable to resolve op for api func %p for obj=%p (%s)",
api_func, eo_obj, efl_class_name_get(eo_obj));
_apply_auto_unref(obj, eo_obj);
eo: Add beta API for auto_unref after a call Before screaming in horror (C++...) here's why we may need this: Efl.Part.part API returns an object that is by definition valid for a single function call only. Enforcing this in practice is actually quite hard as all implementation functions must manually take care of the life-cycle. This is a lot of code in many places and a lot of opportunities to forget to properly handle that life-cycle. Also, this means any invalid function call on a part will leak an object. This API absolutely must remain either "internal" or "beta" and definitely not become abused by applications. On top of that such an API can cause great trouble for bindings like C++. As a consequence, only specially crafted APIs like efl_part() should return an object marked as auto_unref. Alternatively this API could be defined in Eo.h or some other Eo_Internal.h. I placed it in efl_object.eo because it's much more convenient :) (read: I'm lazy) **** Performance notes: Tested with clang & gcc (with -O2), I had a look at the output of perf top, in particular the asm view. I used eo_bench in a loop. My conclusions are: - EINA_LIKELY/UNLIKELY actually works. The jump statement varies according to the expectation. I highly doubt all those ugly goto in eo.c / Eo.h are even useful. - The impact of auto_unref on a call_resolve is so small it doesn't even appear in the trace. It is significant inside call_end, though (obviously, that function is just a few lines long). That function accounts for ~1% to ~4% of all CPU time. The impact of auto_unref in call_end is ~4% of the function time. This means ~0.16% of all CPU time (worst measured case). _efl_object_op_api_id_get simply doesn't show up because of caching, so the extra check there is negligible. PS: I also tested EINA_LIKELY/UNLIKELY by compiling with -O2 and looking at the output with objdump. The flag is well respected, and the jump instructions are what you would expect (no jump for LIKELY and jump for UNLIKELY). Conclusion: The goto's in eo.c only make the code harder to read...
2017-10-13 01:18:41 -07:00
return EFL_NOOP;
}
return op;
}
/* klass is the klass we are working on. hierarchy_klass is the class whe should
* use when validating. */
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)
{
unsigned int i, j;
unsigned int number_of_new_functions = 0;
const Efl_Op_Description *op_desc;
const Efl_Op_Description *op_descs;
const _Efl_Class *override_class;
const void **api_funcs;
Eina_Bool check_equal;
op_descs = ops->descs;
override_class = override_only ? hierarchy_klass : NULL;
DBG("Set functions for class '%s':%p", klass->desc->name, klass);
if (!override_only)
_vtable_insert_empty_funcs(vtable, class_id);
if (!op_descs || !ops->count)
return EINA_TRUE;
#ifdef EO_DEBUG
check_equal = EINA_TRUE;
#else
check_equal = !override_only;
#endif
api_funcs = alloca(ops->count * sizeof(api_funcs[0]));
/* sanity checks */
for (i = 0, op_desc = op_descs; i < ops->count; i++, op_desc++)
{
if (op_desc->api_func == NULL)
{
ERR("Class '%s': NULL API not allowed (NULL->%p '%s').",
klass->desc->name, op_desc->func, _eo_op_desc_name_get(op_desc));
return EINA_FALSE;
}
if (check_equal)
{
for (j = 0; j < i; j++)
{
if (_eo_api_func_equal(op_desc->api_func, api_funcs[j]))
{
ERR("Class '%s': API previously defined (%p->%p '%s').",
klass->desc->name, op_desc->api_func, op_desc->func, _eo_op_desc_name_get(op_desc));
return EINA_FALSE;
}
}
api_funcs[i] = op_desc->api_func;
}
if (_efl_object_api_op_id_get_internal(op_desc->api_func) == EFL_NOOP)
{
number_of_new_functions ++;
}
}
if (!override_only)
eo: rework vtable allocation scheme Summary: with this commit a new way of allocating vtables arrived. The old mechnism was to allocate a table big enough to carry *all* functions at once, in order to not allocate that much memory for functions that are not implemented on a specific klass, dichchains have been used, which can be seens as a 2D matrix, where columns are only allocated if min 1 entry needs to be written, this may have been a good way to allocate back in the day when all this with eo started, however, it showed to not pay off. With this new way, we allocate a array of arrays. the first lvl array is carrying enough slots, that *all* up to the time defined interfaces/classes/abstracts/mixins can be implemented. The second lvl array then has exactly the size of the defined APIs. The second lvl array is obviously only allocated if needed. When comparing the two methods, i messured two things, the usage based on memory allocation for vtable-way-1 and vtable-way-2. Additionally, i checked the overall memory usage of elementary_test using pmap. The first messurement is a little bit more exact. The second messurement is more biased, but captures the whole picture. Memory allocation tracking: vtable-way-1 - vtable-way-2 = 74680 Byte Pmap memory tracking: vtable-way1 - vtable-way-2 = 217088 Byte The second messurement shows a bigger impact, likely because this is also showing off all the sideeffects that we are taking place due to fewer allocations. Depends on D11524 Reviewers: zmike, tasn, stefan_schmidt, woohyun, cedric, raster Subscribers: #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D11535
2020-03-20 04:32:38 -07:00
{
if (number_of_new_functions)
{
//Before setting any real functions, allocate the node that will contain all the functions
_vtable_prepare_empty_node(vtable, number_of_new_functions, class_id);
}
hitmap[class_id] = EINA_TRUE;
}
for (i = 0, j = 0, op_desc = op_descs; i < ops->count; i++, op_desc++)
{
Efl_Object_Op op2 = EFL_NOOP;
short op2_class_id;
/* Get the opid for the function. */
op2 = _efl_object_api_op_id_get_internal(op_desc->api_func);
if (op2 == EFL_NOOP)
{
//functions that do not have a op yet, are considered to be belonging to this class
if (override_only)
{
ERR("Class '%s': Tried overriding a previously undefined function.", klass->desc->name);
return EINA_FALSE;
}
op2 = EFL_OBJECT_OP_CREATE_OP_ID(class_id, j);
eina_spinlock_take(&_ops_storage_lock);
#ifndef _WIN32
eina_hash_add(_ops_storage, &op_desc->api_func, (void *) (uintptr_t) op2);
#else
eina_hash_add(_ops_storage, op_desc->api_func, (void *) (uintptr_t) op2);
#endif
eina_spinlock_release(&_ops_storage_lock);
j ++;
}
#ifdef EO_DEBUG
DBG("%p->%p '%s'", op_desc->api_func, op_desc->func, _eo_op_desc_name_get(op_desc));
#endif
op2_class_id = EFL_OBJECT_OP_CLASS_PART(op2);
//in case we are having a function overwrite for a specific type, copy the relevant vtable
if (!hitmap[op2_class_id])
{
const Eo_Vtable_Node node = vtable->chain[op2_class_id];
_vtable_copy_node(&vtable->chain[op2_class_id], &node);
hitmap[op2_class_id] = EINA_TRUE;
}
if (!_vtable_func_set(vtable, klass, override_class, op2, op_desc->func, EINA_TRUE))
return EINA_FALSE;
}
return EINA_TRUE;
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API 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)
Efl object: change the way we set class's functions. This is another follow up to the investigations of T4227. As stated there, in any PIE (a shared library is one), structures, even const ones end up being written to because of dynamic relocation. This means that using static const structures has actually lead to no savings, only waste. Since we never really needed them, using them made things even worse than just having a different API that doesn't save them. Thus, this commit changes the way we set the functions. Instead of passing a pre-populated struct, we now just have an initialiser function where you set the functions. This on its own doesn't significantly reduce the amount of dirty memory pages for a reason I have yet to uncover, though I believe it's done as a misguided compiler optimisation. However, this design is flexible enough so we can change to another one that is quite ugly, but I have already tested and proven that does that. This patch series doesn't include the better improvement (passing everything on the stack as va_args) because the API was too ugly for me to bear, and I would rather first make sure there is no way to force the compiler to do the right thing here. Unfortunately this commit gives up on useless stricter validation. Before this commit we would make sure that we are only overriding functions correctly defined in our hierarchy. With this one, we don't anymore. This is not a big problem though because this is a check that is also enforced by Eolian. So as long as you are using Eolian, you should be fine. Breaks API and ABI! @feature
2016-08-24 07:59:28 -07:00
{
EO_CLASS_POINTER_GOTO(klass_id, klass, err_klass);
Efl object: change the way we set class's functions. This is another follow up to the investigations of T4227. As stated there, in any PIE (a shared library is one), structures, even const ones end up being written to because of dynamic relocation. This means that using static const structures has actually lead to no savings, only waste. Since we never really needed them, using them made things even worse than just having a different API that doesn't save them. Thus, this commit changes the way we set the functions. Instead of passing a pre-populated struct, we now just have an initialiser function where you set the functions. This on its own doesn't significantly reduce the amount of dirty memory pages for a reason I have yet to uncover, though I believe it's done as a misguided compiler optimisation. However, this design is flexible enough so we can change to another one that is quite ugly, but I have already tested and proven that does that. This patch series doesn't include the better improvement (passing everything on the stack as va_args) because the API was too ugly for me to bear, and I would rather first make sure there is no way to force the compiler to do the right thing here. Unfortunately this commit gives up on useless stricter validation. Before this commit we would make sure that we are only overriding functions correctly defined in our hierarchy. With this one, we don't anymore. This is not a big problem though because this is a check that is also enforced by Eolian. So as long as you are using Eolian, you should be fine. Breaks API and ABI! @feature
2016-08-24 07:59:28 -07:00
Efl_Object_Ops empty_ops = { 0 };
Eina_Bool *hitmap;
// not likely so use goto to alleviate l1 instruction cache of rare code
if (klass->functions_set) goto err_funcs;
Efl object: change the way we set class's functions. This is another follow up to the investigations of T4227. As stated there, in any PIE (a shared library is one), structures, even const ones end up being written to because of dynamic relocation. This means that using static const structures has actually lead to no savings, only waste. Since we never really needed them, using them made things even worse than just having a different API that doesn't save them. Thus, this commit changes the way we set the functions. Instead of passing a pre-populated struct, we now just have an initialiser function where you set the functions. This on its own doesn't significantly reduce the amount of dirty memory pages for a reason I have yet to uncover, though I believe it's done as a misguided compiler optimisation. However, this design is flexible enough so we can change to another one that is quite ugly, but I have already tested and proven that does that. This patch series doesn't include the better improvement (passing everything on the stack as va_args) because the API was too ugly for me to bear, and I would rather first make sure there is no way to force the compiler to do the right thing here. Unfortunately this commit gives up on useless stricter validation. Before this commit we would make sure that we are only overriding functions correctly defined in our hierarchy. With this one, we don't anymore. This is not a big problem though because this is a check that is also enforced by Eolian. So as long as you are using Eolian, you should be fine. Breaks API and ABI! @feature
2016-08-24 07:59:28 -07:00
klass->functions_set = EINA_TRUE;
if (!object_ops) object_ops = &empty_ops;
klass->reflection = reflection_table;
klass->ops_count = object_ops->count;
Efl object: change the way we set class's functions. This is another follow up to the investigations of T4227. As stated there, in any PIE (a shared library is one), structures, even const ones end up being written to because of dynamic relocation. This means that using static const structures has actually lead to no savings, only waste. Since we never really needed them, using them made things even worse than just having a different API that doesn't save them. Thus, this commit changes the way we set the functions. Instead of passing a pre-populated struct, we now just have an initialiser function where you set the functions. This on its own doesn't significantly reduce the amount of dirty memory pages for a reason I have yet to uncover, though I believe it's done as a misguided compiler optimisation. However, this design is flexible enough so we can change to another one that is quite ugly, but I have already tested and proven that does that. This patch series doesn't include the better improvement (passing everything on the stack as va_args) because the API was too ugly for me to bear, and I would rather first make sure there is no way to force the compiler to do the right thing here. Unfortunately this commit gives up on useless stricter validation. Before this commit we would make sure that we are only overriding functions correctly defined in our hierarchy. With this one, we don't anymore. This is not a big problem though because this is a check that is also enforced by Eolian. So as long as you are using Eolian, you should be fine. Breaks API and ABI! @feature
2016-08-24 07:59:28 -07:00
klass->class_id = _UNMASK_ID(klass->header.id) - 1;
Efl object: change the way we set class's functions. This is another follow up to the investigations of T4227. As stated there, in any PIE (a shared library is one), structures, even const ones end up being written to because of dynamic relocation. This means that using static const structures has actually lead to no savings, only waste. Since we never really needed them, using them made things even worse than just having a different API that doesn't save them. Thus, this commit changes the way we set the functions. Instead of passing a pre-populated struct, we now just have an initialiser function where you set the functions. This on its own doesn't significantly reduce the amount of dirty memory pages for a reason I have yet to uncover, though I believe it's done as a misguided compiler optimisation. However, this design is flexible enough so we can change to another one that is quite ugly, but I have already tested and proven that does that. This patch series doesn't include the better improvement (passing everything on the stack as va_args) because the API was too ugly for me to bear, and I would rather first make sure there is no way to force the compiler to do the right thing here. Unfortunately this commit gives up on useless stricter validation. Before this commit we would make sure that we are only overriding functions correctly defined in our hierarchy. With this one, we don't anymore. This is not a big problem though because this is a check that is also enforced by Eolian. So as long as you are using Eolian, you should be fine. Breaks API and ABI! @feature
2016-08-24 07:59:28 -07:00
_vtable_init(&klass->vtable);
if (!klass->vtable.chain) goto err_vtable;
Efl object: change the way we set class's functions. This is another follow up to the investigations of T4227. As stated there, in any PIE (a shared library is one), structures, even const ones end up being written to because of dynamic relocation. This means that using static const structures has actually lead to no savings, only waste. Since we never really needed them, using them made things even worse than just having a different API that doesn't save them. Thus, this commit changes the way we set the functions. Instead of passing a pre-populated struct, we now just have an initialiser function where you set the functions. This on its own doesn't significantly reduce the amount of dirty memory pages for a reason I have yet to uncover, though I believe it's done as a misguided compiler optimisation. However, this design is flexible enough so we can change to another one that is quite ugly, but I have already tested and proven that does that. This patch series doesn't include the better improvement (passing everything on the stack as va_args) because the API was too ugly for me to bear, and I would rather first make sure there is no way to force the compiler to do the right thing here. Unfortunately this commit gives up on useless stricter validation. Before this commit we would make sure that we are only overriding functions correctly defined in our hierarchy. With this one, we don't anymore. This is not a big problem though because this is a check that is also enforced by Eolian. So as long as you are using Eolian, you should be fine. Breaks API and ABI! @feature
2016-08-24 07:59:28 -07:00
hitmap = alloca(klass->vtable.size);
memset(hitmap, 0, klass->vtable.size);
/* Merge in all required vtable entries */
Efl object: change the way we set class's functions. This is another follow up to the investigations of T4227. As stated there, in any PIE (a shared library is one), structures, even const ones end up being written to because of dynamic relocation. This means that using static const structures has actually lead to no savings, only waste. Since we never really needed them, using them made things even worse than just having a different API that doesn't save them. Thus, this commit changes the way we set the functions. Instead of passing a pre-populated struct, we now just have an initialiser function where you set the functions. This on its own doesn't significantly reduce the amount of dirty memory pages for a reason I have yet to uncover, though I believe it's done as a misguided compiler optimisation. However, this design is flexible enough so we can change to another one that is quite ugly, but I have already tested and proven that does that. This patch series doesn't include the better improvement (passing everything on the stack as va_args) because the API was too ugly for me to bear, and I would rather first make sure there is no way to force the compiler to do the right thing here. Unfortunately this commit gives up on useless stricter validation. Before this commit we would make sure that we are only overriding functions correctly defined in our hierarchy. With this one, we don't anymore. This is not a big problem though because this is a check that is also enforced by Eolian. So as long as you are using Eolian, you should be fine. Breaks API and ABI! @feature
2016-08-24 07:59:28 -07:00
{
const _Efl_Class **mro_itr = klass->mro;
/* take over everything from the parent */
if (klass->parent)
{
_vtable_take_over(&klass->vtable, &klass->parent->vtable);
}
/*
* - jump to the mro entry containing the parent
* - everything further from the parent to the next elements is already
* represented in the vtable of the parent.
*/
for ( ; *mro_itr ; mro_itr++)
{
if (*mro_itr == klass->parent)
break;
}
/**
* merge in all the APIs that are extended in the current klass for this first time.
* That means, they are not extended anywhere from the parent further up.
*/
Efl object: change the way we set class's functions. This is another follow up to the investigations of T4227. As stated there, in any PIE (a shared library is one), structures, even const ones end up being written to because of dynamic relocation. This means that using static const structures has actually lead to no savings, only waste. Since we never really needed them, using them made things even worse than just having a different API that doesn't save them. Thus, this commit changes the way we set the functions. Instead of passing a pre-populated struct, we now just have an initialiser function where you set the functions. This on its own doesn't significantly reduce the amount of dirty memory pages for a reason I have yet to uncover, though I believe it's done as a misguided compiler optimisation. However, this design is flexible enough so we can change to another one that is quite ugly, but I have already tested and proven that does that. This patch series doesn't include the better improvement (passing everything on the stack as va_args) because the API was too ugly for me to bear, and I would rather first make sure there is no way to force the compiler to do the right thing here. Unfortunately this commit gives up on useless stricter validation. Before this commit we would make sure that we are only overriding functions correctly defined in our hierarchy. With this one, we don't anymore. This is not a big problem though because this is a check that is also enforced by Eolian. So as long as you are using Eolian, you should be fine. Breaks API and ABI! @feature
2016-08-24 07:59:28 -07:00
for ( mro_itr-- ; mro_itr > klass->mro ; mro_itr--)
{
_vtable_merge_defined_api(&klass->vtable, &(*mro_itr)->vtable, hitmap);
}
/*
* add slots for the interfaces and mixins we are inheriting from
*/
for (int i = 0; klass->extensions[i]; i++)
{
const _Efl_Class *ext = klass->extensions[i];
/*for all extensions of the class, ensure that *at least* empty vtables are available, so the efl_isa calls do succeed*/
_vtable_merge_empty(&klass->vtable, &ext->vtable, hitmap);
}
Efl object: change the way we set class's functions. This is another follow up to the investigations of T4227. As stated there, in any PIE (a shared library is one), structures, even const ones end up being written to because of dynamic relocation. This means that using static const structures has actually lead to no savings, only waste. Since we never really needed them, using them made things even worse than just having a different API that doesn't save them. Thus, this commit changes the way we set the functions. Instead of passing a pre-populated struct, we now just have an initialiser function where you set the functions. This on its own doesn't significantly reduce the amount of dirty memory pages for a reason I have yet to uncover, though I believe it's done as a misguided compiler optimisation. However, this design is flexible enough so we can change to another one that is quite ugly, but I have already tested and proven that does that. This patch series doesn't include the better improvement (passing everything on the stack as va_args) because the API was too ugly for me to bear, and I would rather first make sure there is no way to force the compiler to do the right thing here. Unfortunately this commit gives up on useless stricter validation. Before this commit we would make sure that we are only overriding functions correctly defined in our hierarchy. With this one, we don't anymore. This is not a big problem though because this is a check that is also enforced by Eolian. So as long as you are using Eolian, you should be fine. Breaks API and ABI! @feature
2016-08-24 07:59:28 -07:00
}
{
unsigned int i;
Efl object: change the way we set class's functions. This is another follow up to the investigations of T4227. As stated there, in any PIE (a shared library is one), structures, even const ones end up being written to because of dynamic relocation. This means that using static const structures has actually lead to no savings, only waste. Since we never really needed them, using them made things even worse than just having a different API that doesn't save them. Thus, this commit changes the way we set the functions. Instead of passing a pre-populated struct, we now just have an initialiser function where you set the functions. This on its own doesn't significantly reduce the amount of dirty memory pages for a reason I have yet to uncover, though I believe it's done as a misguided compiler optimisation. However, this design is flexible enough so we can change to another one that is quite ugly, but I have already tested and proven that does that. This patch series doesn't include the better improvement (passing everything on the stack as va_args) because the API was too ugly for me to bear, and I would rather first make sure there is no way to force the compiler to do the right thing here. Unfortunately this commit gives up on useless stricter validation. Before this commit we would make sure that we are only overriding functions correctly defined in our hierarchy. With this one, we don't anymore. This is not a big problem though because this is a check that is also enforced by Eolian. So as long as you are using Eolian, you should be fine. Breaks API and ABI! @feature
2016-08-24 07:59:28 -07:00
for (i = 0; i < object_ops->count; i++)
{
Efl_Object_Op op = _efl_object_api_op_id_get_internal(object_ops->descs[i].api_func);
if (op == EFL_NOOP) continue; //EFL_NOOP means that this function is not yet defined, this will be handled later
short class_id = EFL_OBJECT_OP_CLASS_PART(op);
if (klass->vtable.chain[class_id].count == 0)
{
const _Efl_Class *required_klass = _eo_classes[class_id];
/* in case this type is not already inherited, error on everything that is not a mixin */
if (klass->desc->type == EFL_CLASS_TYPE_MIXIN)
{
/* this is when a mixin implemets a regular api, we just prepare a empty node, the rest will be implemented later */
_vtable_prepare_empty_node(&klass->vtable, required_klass->vtable.chain[class_id].count, class_id);
hitmap[class_id] = EINA_TRUE;
}
else
{
ERR("There is an API implemented, whoms type is not part of this class. %s vs. %s", klass->desc->name, required_klass->desc->name);
_vtable_prepare_empty_node(&klass->vtable, required_klass->vtable.chain[class_id].count, class_id);
hitmap[class_id] = EINA_TRUE;
}
}
}
}
return _eo_class_funcs_set(&klass->vtable, object_ops, klass, klass, EINA_FALSE, klass->class_id, hitmap);
err_funcs:
ERR("Class %s already had its functions set..", klass->desc->name);
return EINA_FALSE;
err_klass:
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
_EO_POINTER_ERR(klass_id, "Class (%p) is an invalid ref.", klass_id);
return EINA_FALSE;
err_vtable:
ERR("failed to allocate vtable for class '%s'", klass->desc->name);
return EINA_FALSE;
Efl object: change the way we set class's functions. This is another follow up to the investigations of T4227. As stated there, in any PIE (a shared library is one), structures, even const ones end up being written to because of dynamic relocation. This means that using static const structures has actually lead to no savings, only waste. Since we never really needed them, using them made things even worse than just having a different API that doesn't save them. Thus, this commit changes the way we set the functions. Instead of passing a pre-populated struct, we now just have an initialiser function where you set the functions. This on its own doesn't significantly reduce the amount of dirty memory pages for a reason I have yet to uncover, though I believe it's done as a misguided compiler optimisation. However, this design is flexible enough so we can change to another one that is quite ugly, but I have already tested and proven that does that. This patch series doesn't include the better improvement (passing everything on the stack as va_args) because the API was too ugly for me to bear, and I would rather first make sure there is no way to force the compiler to do the right thing here. Unfortunately this commit gives up on useless stricter validation. Before this commit we would make sure that we are only overriding functions correctly defined in our hierarchy. With this one, we don't anymore. This is not a big problem though because this is a check that is also enforced by Eolian. So as long as you are using Eolian, you should be fine. Breaks API and ABI! @feature
2016-08-24 07:59:28 -07:00
}
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)
2013-08-01 00:47:21 -07:00
{
const char *func_name = __func__;
_Eo_Object *obj;
Eo_Stack_Frame *fptr = NULL;
if (is_fallback) fptr = _efl_add_fallback_stack_push(NULL);
if (class_overrides)
{
const Efl_Class *override = eina_hash_find(class_overrides, &klass_id);
if (override) klass_id = override;
}
EO_CLASS_POINTER_GOTO_PROXY(klass_id, klass, err_klass);
2013-08-01 00:47:21 -07:00
// Check that in the case of efl_add we do pass a parent.
if (!ref && !parent_id)
ERR("Creation of '%s' object at line %i in '%s' is done without parent. This should use efl_add_ref.",
klass->desc->name, line, file);
2013-08-01 00:47:21 -07:00
if (parent_id)
{
EO_OBJ_POINTER_GOTO_PROXY(parent_id, parent, err_parent);
2013-08-01 00:47:21 -07:00
}
// not likely so use goto to alleviate l1 instruction cache of rare code
if (EINA_UNLIKELY(klass->desc->type != EFL_CLASS_TYPE_REGULAR))
goto err_noreg;
2013-08-01 00:47:21 -07:00
eina_spinlock_take(&klass->objects.trash_lock);
obj = eina_trash_pop(&klass->objects.trash);
if (obj)
{
memset(obj, 0, klass->obj_size);
klass->objects.trash_count--;
}
else
{
obj = calloc(1, klass->obj_size);
}
eina_spinlock_release(&klass->objects.trash_lock);
obj->opt = eina_cow_alloc(efl_object_optional_cow);
_efl_ref(obj);
2013-08-01 00:47:21 -07:00
obj->klass = klass;
eo - make eo id table TLS private data for thread safety and speed This moved all the eoid tables, eoid lookup caches, generation count information ad eo_isa cache into a TLS segment of memory that is thread private. There is also a shared domain for EO objects that all threads can access, but it has an added cost of a lock. This means objects accessed outside the thread they were created in cannot be accessed by another thread unless they are adopted in temporarily, or create4d with the shared domain active at the time of creation. child objects will use their parent object domain if created with a parent object passed in. If you were accessing EO (EFL) objects across threads before then this will actually now cause your code to fail as it was invalid before to do this as no actual objects were threadsafe in EFL, so this will force things to "fail early". ecore_thread_main_loop_begin() and end() still work as this uses the eo domain adoption features to temporarily adopt a domain during this section and then return it when done. This returns speed back to eo brining the overhead in my tests of lookup for the elm genlist autobounce test in elementary from about 5-7% down to 2.5-2.6%. A steep drop. This does not mean everything is perfect. Still to do are: 1. Tests in the test suite 2. Some API's to help for sending objects from thread to thread 3. Make the eo call cache TLS data to make it also safe 4. Look at other locks in eo and probably move them to TLS data 5. Make eo resolve and call wrappers that call the real method func do recursive mutex wrapping of the given object IF it is a shared object to provide threadsafety transparently for shared objects (but adding some overhead as a result) 6. Test test est, and that is why this commit is going in now for wider testing 7. Decide how to make this work with sending IPC (between threads) 8. Deciding what makes an object sendable (a sendable property in base?) 9. Deciding what makes an object shareable (a sharable property in base?)
2016-09-07 01:53:33 -07:00
obj->header.id = _eo_id_allocate(obj, parent_id);
Eo *eo_id = _eo_obj_id_get(obj);
2013-08-01 00:47:21 -07:00
_eo_log_obj_ref_op(obj, EO_REF_OP_NEW);
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
2013-08-01 00:47:21 -07:00
_eo_condtor_reset(obj);
efl_ref(eo_id);
/* Reference for the parent if is_ref is done in _efl_add_end */
if (parent_id) efl_parent_set(eo_id, parent_id);
/* eo_id can change here. Freeing is done on the resolved object. */
if (!substitute_ctor) eo_id = efl_constructor(eo_id);
else eo_id = substitute_ctor(sub_ctor_data, eo_id);
// not likely so use goto to alleviate l1 instruction cache of rare code
if (!eo_id) goto err_noid;
// not likely so use goto to alleviate l1 instruction cache of rare code
else if (eo_id != _eo_obj_id_get(obj)) goto ok_nomatch;
ok_nomatch_back:
if (is_fallback) fptr->obj = eo_id;
if (parent_id) EO_OBJ_DONE(parent_id);
return eo_id;
ok_nomatch:
{
EO_OBJ_POINTER_GOTO_PROXY(eo_id, new_obj, err_newid);
_efl_ref(new_obj);
efl_ref(eo_id);
/* We might have two refs on the old object at this point. */
efl_parent_set((Eo *) obj->header.id, NULL);
efl_unref(_eo_obj_id_get(obj));
_efl_unref(obj);
EO_OBJ_DONE(eo_id);
}
goto ok_nomatch_back;
err_noid:
ERR("in %s:%d: Object of class '%s' - Error while constructing object",
file, line, klass->desc->name);
/* We might have two refs at this point. */
efl_parent_set((Eo *) obj->header.id, NULL);
efl_unref(_eo_obj_id_get(obj));
_efl_unref(obj);
err_newid:
if (parent_id) EO_OBJ_DONE(parent_id);
return NULL;
err_noreg:
ERR("in %s:%d: Class '%s' is not instantiate-able. Aborting.", file, line, klass->desc->name);
if (parent_id) EO_OBJ_DONE(parent_id);
return NULL;
err_klass:
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
_EO_POINTER_ERR(klass_id, "in %s:%d: Class (%p) is an invalid ref.", file, line, klass_id);
err_parent:
return NULL;
2013-08-01 00:47:21 -07:00
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API 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)
{
return _efl_add_internal_start_do(file, line, klass_id, parent_id, ref, is_fallback, NULL, NULL);
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API 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)
{
return _efl_add_internal_start_do(file, line, klass_id, parent_id, ref, is_fallback, substitute_ctor, sub_ctor_data);
}
static Eo *
_efl_add_internal_end(Eo *eo_id, Eo *finalized_id)
2013-08-01 00:47:21 -07:00
{
EO_OBJ_POINTER_RETURN_VAL(eo_id, obj, NULL);
// rare so move error handling to end to save l1 instruction cache
if (!obj->condtor_done) goto err_condtor;
if (!finalized_id)
{
// XXX: Given EFL usage of objects, construction is a perfectly valid thing
// to do. we shouldn't complain about it as handling a NULL obj creation is
// the job of the caller. a perfect example here is ecore_con and ecore_ipc
// where you create a con or ipc obj then set up type/destination/port and
// the finalize of the constructor does the actual connect and thus this
// fails or succeeds based on if service is there.
//
// until there is a better solution - don't complain here.
//
// ERR("Object of class '%s' - Finalizing the object failed.",
// klass->desc->name);
goto cleanup;
2013-08-01 00:47:21 -07:00
}
obj->finalized = EINA_TRUE;
_efl_unref(obj);
EO_OBJ_DONE(eo_id);
return (Eo *)eo_id;
err_condtor:
{
const _Efl_Class *klass = obj->klass;
ERR("Object of class '%s' - Not all of the object constructors have been executed.",
klass->desc->name);
}
cleanup:
efl_parent_set((Eo *) obj->header.id, NULL);
efl_unref((Eo *) obj->header.id);
_efl_unref(obj);
EO_OBJ_DONE(eo_id);
return NULL;
2013-08-01 00:47:21 -07:00
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API Eo *
_efl_add_end(Eo *eo_id, Eina_Bool is_ref, Eina_Bool is_fallback)
{
if (!eo_id) return NULL;
Eo *ret = efl_finalize(eo_id);
ret = _efl_add_internal_end(eo_id, ret);
if (ret && !is_ref)
{
efl_unref(ret);
}
if (is_fallback)
{
_efl_add_fallback_stack_pop();
}
return ret;
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API void
efl_reuse(const Eo *eo_id)
{
Eo *obj = (Eo *) eo_id;
EO_OBJ_POINTER_RETURN(obj, _obj);
efl_object_override(obj, NULL);
_efl_object_reuse(_obj);
#ifdef EO_DEBUG
_eo_log_obj_ref_op(_obj, EO_REF_OP_REUSE);
#endif
EO_OBJ_DONE(eo_id);
}
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
void
_eo_free(_Eo_Object *obj, Eina_Bool manual_free EINA_UNUSED)
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
{
_Efl_Class *klass = (_Efl_Class*) obj->klass;
_eo_log_obj_ref_op(obj, EO_REF_OP_FREE);
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
#ifdef EO_DEBUG
if (manual_free)
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
{
Eo *obj_id = _eo_obj_id_get(obj);
if (obj->datarefcount)
{
ERR("Object %p data still referenced %d time(s).", obj_id, obj->datarefcount);
}
while (obj->xrefs)
{
Eina_Inlist *nitr = obj->xrefs->next;
Eo_Xref_Node *xref = EINA_INLIST_CONTAINER_GET(obj->data_xrefs, Eo_Xref_Node);
ERR("Object %p is still referenced by object %p. Origin: %s:%d",
obj_id, xref->ref_obj, xref->file, xref->line);
eina_freeq_ptr_main_add(xref, free, sizeof(*xref));
obj->xrefs = nitr;
}
while (obj->data_xrefs)
{
Eina_Inlist *nitr = obj->data_xrefs->next;
Eo_Xref_Node *xref = EINA_INLIST_CONTAINER_GET(obj->data_xrefs, Eo_Xref_Node);
if (obj_id == xref->ref_obj)
{
WRN("Object %p still has a reference to its own data (subclass: %s). Origin: %s:%d",
obj_id, xref->data_klass, xref->file, xref->line);
}
else
{
ERR("Data of object %p (subclass: %s) is still referenced by object %p. Origin: %s:%d",
obj_id, xref->data_klass, xref->ref_obj, xref->file, xref->line);
}
eina_freeq_ptr_main_add(xref, free, sizeof(*xref));
obj->data_xrefs = nitr;
}
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
}
#endif
if (obj->opt && _obj_is_override(obj))
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
{
_vtable_free(obj->opt->vtable, &obj->klass->vtable);
EO_OPTIONAL_COW_SET(obj, vtable, NULL);
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
}
_eo_id_release((Eo_Id) _eo_obj_id_get(obj));
eina_cow_free(efl_object_optional_cow, (Eina_Cow_Data *) &obj->opt);
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
eina_spinlock_take(&klass->objects.trash_lock);
if ((klass->objects.trash_count <= 8) && (EINA_LIKELY(!_eo_trash_bypass)))
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
{
eina_trash_push(&klass->objects.trash, obj);
klass->objects.trash_count++;
}
else
{
eina_freeq_ptr_main_add(obj, free, klass->obj_size);
}
eina_spinlock_release(&klass->objects.trash_lock);
}
2013-07-18 00:10:07 -07:00
/*****************************************************************************/
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API const Efl_Class *
efl_class_get(const Eo *eo_id)
{
const Efl_Class *klass;
if (_eo_is_a_class(eo_id))
{
EO_CLASS_POINTER_GOTO(eo_id, _klass, err_klass);
return EFL_CLASS_CLASS;
}
EO_OBJ_POINTER_GOTO(eo_id, obj, err_obj);
klass = _eo_class_id_get(obj->klass);
EO_OBJ_DONE(eo_id);
return klass;
err_klass:
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
_EO_POINTER_ERR(eo_id, "Class (%p) is an invalid ref.", eo_id);
err_obj:
return NULL;
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API const char *
efl_class_name_get(const Efl_Class *eo_id)
{
const _Efl_Class *klass;
if (_eo_is_a_class(eo_id))
{
EO_CLASS_POINTER_GOTO(eo_id, _klass, err_klass);
klass = _klass;
}
else
{
EO_OBJ_POINTER_GOTO(eo_id, obj, err_obj);
klass = obj->klass;
EO_OBJ_DONE(eo_id);
}
return klass->desc->name;
err_klass:
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
_EO_POINTER_ERR(eo_id, "Class (%p) is an invalid ref.", eo_id);
err_obj:
return NULL;
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API size_t
efl_class_memory_size_get(const Efl_Class *eo_id)
{
const _Efl_Class *klass;
if (_eo_is_a_class(eo_id))
{
EO_CLASS_POINTER_GOTO(eo_id, _klass, err_klass);
klass = _klass;
}
else
{
EO_OBJ_POINTER_GOTO(eo_id, obj, err_obj);
klass = obj->klass;
EO_OBJ_DONE(eo_id);
}
return klass->obj_size;
err_klass:
_EO_POINTER_ERR(eo_id, "Class (%p) is an invalid ref.", eo_id);
err_obj:
return 0;
}
static Eina_Bool
_eo_class_mro_has(const _Efl_Class *klass, const _Efl_Class *find)
{
const _Efl_Class **itr;
for (itr = klass->mro ; *itr ; itr++)
{
if (*itr == find)
{
return EINA_TRUE;
}
}
return EINA_FALSE;
}
static Eina_List *
_eo_class_list_remove_duplicates(Eina_List* list)
{
Eina_List *itr1, *itr2, *itr2n;
itr1 = eina_list_last(list);
while (itr1)
{
itr2 = eina_list_prev(itr1);
while (itr2)
{
itr2n = eina_list_prev(itr2);
if (eina_list_data_get(itr1) == eina_list_data_get(itr2))
{
list = eina_list_remove_list(list, itr2);
}
itr2 = itr2n;
}
itr1 = eina_list_prev(itr1);
}
return list;
}
static Eina_List *
_eo_class_mro_add(Eina_List *mro, const _Efl_Class *klass)
{
if (!klass)
return mro;
mro = eina_list_append(mro, klass);
/* Recursively add MIXINS extensions. */
{
const _Efl_Class **extn_itr;
for (extn_itr = klass->extensions ; *extn_itr ; extn_itr++)
{
const _Efl_Class *extn = *extn_itr;
if (extn->desc->type == EFL_CLASS_TYPE_MIXIN)
mro = _eo_class_mro_add(mro, extn);
}
}
mro = _eo_class_mro_add(mro, klass->parent);
return mro;
}
static Eina_List *
_eo_class_mro_init(const Efl_Class_Description *desc, const _Efl_Class *parent, Eina_List *extensions)
{
Eina_List *mro = NULL;
Eina_List *extn_itr = NULL;
Eina_List *extn_pos = NULL;
const _Efl_Class *extn = NULL;
/* Add MIXINS extensions. */
EINA_LIST_FOREACH(extensions, extn_itr, extn)
{
if (extn->desc->type != EFL_CLASS_TYPE_MIXIN)
continue;
mro = _eo_class_mro_add(mro, extn);
extn_pos = eina_list_append(extn_pos, eina_list_last(mro));
}
/* Check if we can create a consistent mro */
{
Eina_List *itr = extn_pos;
EINA_LIST_FOREACH(extensions, extn_itr, extn)
{
if (extn->desc->type != EFL_CLASS_TYPE_MIXIN)
continue;
/* Get the first one after the extension. */
Eina_List *extn_list = eina_list_next(eina_list_data_get(itr));
/* If we found the extension again. */
if (eina_list_data_find_list(extn_list, extn))
{
eina_list_free(mro);
eina_list_free(extn_pos);
ERR("Cannot create a consistent method resolution order for class '%s' because of '%s'.", desc->name, extn->desc->name);
return NULL;
}
itr = eina_list_next(itr);
}
}
eina_list_free(extn_pos);
mro = _eo_class_mro_add(mro, parent);
mro = _eo_class_list_remove_duplicates(mro);
/* Will be replaced with the actual class pointer */
mro = eina_list_prepend(mro, NULL);
return mro;
}
Efl object: change the way we set class's functions. This is another follow up to the investigations of T4227. As stated there, in any PIE (a shared library is one), structures, even const ones end up being written to because of dynamic relocation. This means that using static const structures has actually lead to no savings, only waste. Since we never really needed them, using them made things even worse than just having a different API that doesn't save them. Thus, this commit changes the way we set the functions. Instead of passing a pre-populated struct, we now just have an initialiser function where you set the functions. This on its own doesn't significantly reduce the amount of dirty memory pages for a reason I have yet to uncover, though I believe it's done as a misguided compiler optimisation. However, this design is flexible enough so we can change to another one that is quite ugly, but I have already tested and proven that does that. This patch series doesn't include the better improvement (passing everything on the stack as va_args) because the API was too ugly for me to bear, and I would rather first make sure there is no way to force the compiler to do the right thing here. Unfortunately this commit gives up on useless stricter validation. Before this commit we would make sure that we are only overriding functions correctly defined in our hierarchy. With this one, we don't anymore. This is not a big problem though because this is a check that is also enforced by Eolian. So as long as you are using Eolian, you should be fine. Breaks API and ABI! @feature
2016-08-24 07:59:28 -07:00
static Eina_Bool
_eo_class_initializer(_Efl_Class *klass)
{
if (klass->desc->class_initializer)
return klass->desc->class_initializer(_eo_class_id_get(klass));
return EINA_TRUE;
}
static void
_eo_class_constructor(_Efl_Class *klass)
{
klass->constructed = EINA_TRUE;
klass->construction_thread = eina_thread_self();
if (klass->desc->class_constructor)
2013-07-29 14:52:46 -07:00
klass->desc->class_constructor(_eo_class_id_get(klass));
}
static void
eo_class_free(_Efl_Class *klass)
{
void *data;
Eina_Thread self = eina_thread_self();
if ((self != _efl_object_main_thread) &&
(self != klass->construction_thread))
CRI("Calling class deconstructor from thread that did not call constructor and is not main thread!\n"
"This will probably crash!");
if (klass->constructed)
{
if (klass->desc->class_destructor)
klass->desc->class_destructor(_eo_class_id_get(klass));
_vtable_mro_free(klass);
_vtable_free(&klass->vtable, NULL);
}
EINA_TRASH_CLEAN(&klass->objects.trash, data)
eina_freeq_ptr_main_add(data, free, klass->obj_size);
EINA_TRASH_CLEAN(&klass->iterators.trash, data)
eina_freeq_ptr_main_add(data, free, 0);
eina_spinlock_free(&klass->objects.trash_lock);
eina_spinlock_free(&klass->iterators.trash_lock);
eina_freeq_ptr_main_add(klass, free, 0);
}
static inline void
_eo_classes_release(void)
{
#ifdef HAVE_MMAP
# ifdef HAVE_VALGRIND
if (RUNNING_ON_VALGRIND) free(_eo_classes);
else
# endif
{
size_t size;
size = _eo_classes_alloc * sizeof(_Efl_Class *);
if (_eo_classes) munmap(_eo_classes, size);
}
#else
free(_eo_classes);
#endif
_eo_classes = NULL;
_eo_classes_last_id = 0;
_eo_classes_alloc = 0;
}
static inline void
_eo_classes_expand(void)
{
unsigned char *ptr;
size_t newsize, psize;
_eo_classes_last_id++;
if (_eo_classes_last_id <= _eo_classes_alloc) return;
psize = _eo_classes_alloc * sizeof(_Efl_Class *);
#ifdef HAVE_MMAP
# ifdef HAVE_VALGRIND
if (RUNNING_ON_VALGRIND)
{
_eo_classes_alloc += 128;
newsize = _eo_classes_alloc * sizeof(_Efl_Class *);
ptr = realloc(_eo_classes, newsize);
if (!ptr)
{
ERR("realloc of eo class table region faile!!");
abort();
}
}
else
# endif
{
_eo_classes_alloc += (MEM_PAGE_SIZE / sizeof(_Efl_Class *));
newsize = _eo_classes_alloc * sizeof(_Efl_Class *);
ptr = mmap(NULL, newsize, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANON, -1, 0);
if (ptr == MAP_FAILED)
{
ERR("mmap of eo class table region failed!");
abort();
}
if (psize > 0) memcpy(ptr, _eo_classes, psize);
if (_eo_classes) munmap(_eo_classes, psize);
}
#else
_eo_classes_alloc += 128;
newsize = _eo_classes_alloc * sizeof(_Efl_Class *);
ptr = realloc(_eo_classes, newsize);
if (!ptr)
{
ERR("realloc of eo class table region faile!!");
abort();
}
#endif
memset(ptr + psize, 0, newsize - psize);
_eo_classes = (_Efl_Class **)ptr;
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API const Efl_Class *
efl_class_new(const Efl_Class_Description *desc, const Efl_Class *parent_id, ...)
{
_Efl_Class *klass;
va_list p_list;
size_t extn_sz, mro_sz, mixins_sz;
Eina_List *extn_list, *mro, *mixins;
_Efl_Class *parent = NULL;
EINA_SAFETY_ON_NULL_RETURN_VAL(desc, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(desc->name, NULL);
if (parent_id)
{
parent = _eo_class_pointer_get(parent_id);
if (!parent)
return NULL;
}
/* Check restrictions on Interface types. */
if (desc->type == EFL_CLASS_TYPE_INTERFACE)
{
EINA_SAFETY_ON_FALSE_RETURN_VAL(!desc->data_size, NULL);
}
/* Check parent */
if (parent)
{
/* Verify the inheritance is allowed. */
switch (desc->type)
{
case EFL_CLASS_TYPE_REGULAR:
case EFL_CLASS_TYPE_REGULAR_NO_INSTANT:
if ((parent->desc->type != EFL_CLASS_TYPE_REGULAR) &&
(parent->desc->type != EFL_CLASS_TYPE_REGULAR_NO_INSTANT))
{
ERR("Regular classes ('%s') aren't allowed to inherit from non-regular classes ('%s').",
desc->name, parent->desc->name);
return NULL;
}
break;
case EFL_CLASS_TYPE_INTERFACE:
case EFL_CLASS_TYPE_MIXIN:
if ((parent->desc->type != EFL_CLASS_TYPE_INTERFACE) &&
(parent->desc->type != EFL_CLASS_TYPE_MIXIN))
{
ERR("Non-regular classes ('%s') aren't allowed to inherit from regular classes ('%s').",
desc->name, parent->desc->name);
return NULL;
}
break;
default:
ERR("type cannot be INVALID");
return NULL;
}
}
/* Build class extensions list */
{
DBG("Started building extensions list for class '%s'", desc->name);
extn_list = NULL;
const _Efl_Class *extn = NULL;
const Eo_Id *extn_id = NULL;
va_start(p_list, parent_id);
extn_id = va_arg(p_list, Eo_Id *);
while (extn_id)
{
extn = _eo_class_pointer_get((Efl_Class *)extn_id);
if (EINA_LIKELY(extn != NULL))
{
switch (extn->desc->type)
{
case EFL_CLASS_TYPE_REGULAR_NO_INSTANT:
case EFL_CLASS_TYPE_REGULAR:
case EFL_CLASS_TYPE_INTERFACE:
case EFL_CLASS_TYPE_MIXIN:
extn_list = eina_list_append(extn_list, extn);
break;
default:
ERR("type cannot be INVALID");
va_end(p_list);
return NULL;
}
}
extn_id = va_arg(p_list, Eo_Id *);
}
va_end(p_list);
extn_list = _eo_class_list_remove_duplicates(extn_list);
extn_sz = sizeof(_Efl_Class *) * (eina_list_count(extn_list) + 1);
DBG("Finished building extensions list for class '%s'", desc->name);
}
/* Prepare mro list */
{
DBG("Started building MRO list for class '%s'", desc->name);
mro = _eo_class_mro_init(desc, parent, extn_list);
if (!mro)
{
eina_list_free(extn_list);
return NULL;
}
mro_sz = sizeof(_Efl_Class *) * (eina_list_count(mro) + 1);
DBG("Finished building MRO list for class '%s'", desc->name);
}
/* Prepare mixins list */
{
Eina_List *itr;
const _Efl_Class *kls_itr;
DBG("Started building Mixins list for class '%s'", desc->name);
mixins = NULL;
EINA_LIST_FOREACH(mro, itr, kls_itr)
{
if ((kls_itr) && (kls_itr->desc->type == EFL_CLASS_TYPE_MIXIN) &&
(kls_itr->desc->data_size > 0))
mixins = eina_list_append(mixins, kls_itr);
}
mixins_sz = sizeof(Eo_Extension_Data_Offset) * (eina_list_count(mixins) + 1);
if ((desc->type == EFL_CLASS_TYPE_MIXIN) && (desc->data_size > 0))
mixins_sz += sizeof(Eo_Extension_Data_Offset);
DBG("Finished building Mixins list for class '%s'", desc->name);
}
klass = calloc(1, _eo_class_sz + extn_sz + mro_sz + mixins_sz);
eina_spinlock_new(&klass->objects.trash_lock);
eina_spinlock_new(&klass->iterators.trash_lock);
klass->parent = parent;
klass->desc = desc;
klass->extensions = (const _Efl_Class **) ((char *) klass + _eo_class_sz);
klass->mro = (const _Efl_Class **) ((char *) klass->extensions + extn_sz);
klass->extn_data_off = (Eo_Extension_Data_Offset *) ((char *) klass->mro + mro_sz);
Efl object: change the way we set class's functions. This is another follow up to the investigations of T4227. As stated there, in any PIE (a shared library is one), structures, even const ones end up being written to because of dynamic relocation. This means that using static const structures has actually lead to no savings, only waste. Since we never really needed them, using them made things even worse than just having a different API that doesn't save them. Thus, this commit changes the way we set the functions. Instead of passing a pre-populated struct, we now just have an initialiser function where you set the functions. This on its own doesn't significantly reduce the amount of dirty memory pages for a reason I have yet to uncover, though I believe it's done as a misguided compiler optimisation. However, this design is flexible enough so we can change to another one that is quite ugly, but I have already tested and proven that does that. This patch series doesn't include the better improvement (passing everything on the stack as va_args) because the API was too ugly for me to bear, and I would rather first make sure there is no way to force the compiler to do the right thing here. Unfortunately this commit gives up on useless stricter validation. Before this commit we would make sure that we are only overriding functions correctly defined in our hierarchy. With this one, we don't anymore. This is not a big problem though because this is a check that is also enforced by Eolian. So as long as you are using Eolian, you should be fine. Breaks API and ABI! @feature
2016-08-24 07:59:28 -07:00
if (klass->parent)
{
/* FIXME: Make sure this alignment is enough. */
klass->data_offset = klass->parent->data_offset +
EO_ALIGN_SIZE(klass->parent->desc->data_size);
}
else
{
/* Data starts after the object size. */
klass->data_offset = _eo_sz;
}
mro = eina_list_remove(mro, NULL);
mro = eina_list_prepend(mro, klass);
if ((desc->type == EFL_CLASS_TYPE_MIXIN) && (desc->data_size > 0))
{
mixins = eina_list_prepend(mixins, klass);
}
/* Copy the extensions and free the list */
{
const _Efl_Class *extn = NULL;
const _Efl_Class **extn_itr = klass->extensions;
EINA_LIST_FREE(extn_list, extn)
{
*(extn_itr++) = extn;
DBG("Added '%s' extension", extn->desc->name);
}
*(extn_itr) = NULL;
}
/* Copy the mro and free the list. */
{
const _Efl_Class *kls_itr = NULL;
const _Efl_Class **mro_itr = klass->mro;
EINA_LIST_FREE(mro, kls_itr)
{
*(mro_itr++) = kls_itr;
DBG("Added '%s' to MRO", kls_itr->desc->name);
}
*(mro_itr) = NULL;
}
size_t extn_data_off = klass->data_offset;
if (klass->desc->type != EFL_CLASS_TYPE_MIXIN)
{
extn_data_off += EO_ALIGN_SIZE(klass->desc->data_size);
}
/* Feed the mixins data offsets and free the mixins list. */
{
const _Efl_Class *kls_itr = NULL;
Eo_Extension_Data_Offset *extn_data_itr = klass->extn_data_off;
EINA_LIST_FREE(mixins, kls_itr)
{
extn_data_itr->klass = kls_itr;
extn_data_itr->offset = extn_data_off;
extn_data_off += EO_ALIGN_SIZE(extn_data_itr->klass->desc->data_size);
extn_data_itr++;
DBG("Added '%s' to Data Offset info", kls_itr->desc->name);
}
extn_data_itr->klass = 0;
extn_data_itr->offset = 0;
}
klass->obj_size = extn_data_off;
Efl object: change the way we set class's functions. This is another follow up to the investigations of T4227. As stated there, in any PIE (a shared library is one), structures, even const ones end up being written to because of dynamic relocation. This means that using static const structures has actually lead to no savings, only waste. Since we never really needed them, using them made things even worse than just having a different API that doesn't save them. Thus, this commit changes the way we set the functions. Instead of passing a pre-populated struct, we now just have an initialiser function where you set the functions. This on its own doesn't significantly reduce the amount of dirty memory pages for a reason I have yet to uncover, though I believe it's done as a misguided compiler optimisation. However, this design is flexible enough so we can change to another one that is quite ugly, but I have already tested and proven that does that. This patch series doesn't include the better improvement (passing everything on the stack as va_args) because the API was too ugly for me to bear, and I would rather first make sure there is no way to force the compiler to do the right thing here. Unfortunately this commit gives up on useless stricter validation. Before this commit we would make sure that we are only overriding functions correctly defined in our hierarchy. With this one, we don't anymore. This is not a big problem though because this is a check that is also enforced by Eolian. So as long as you are using Eolian, you should be fine. Breaks API and ABI! @feature
2016-08-24 07:59:28 -07:00
{
Eo_Id new_id;
eina_lock_take(&_efl_class_creation_lock);
Efl object: change the way we set class's functions. This is another follow up to the investigations of T4227. As stated there, in any PIE (a shared library is one), structures, even const ones end up being written to because of dynamic relocation. This means that using static const structures has actually lead to no savings, only waste. Since we never really needed them, using them made things even worse than just having a different API that doesn't save them. Thus, this commit changes the way we set the functions. Instead of passing a pre-populated struct, we now just have an initialiser function where you set the functions. This on its own doesn't significantly reduce the amount of dirty memory pages for a reason I have yet to uncover, though I believe it's done as a misguided compiler optimisation. However, this design is flexible enough so we can change to another one that is quite ugly, but I have already tested and proven that does that. This patch series doesn't include the better improvement (passing everything on the stack as va_args) because the API was too ugly for me to bear, and I would rather first make sure there is no way to force the compiler to do the right thing here. Unfortunately this commit gives up on useless stricter validation. Before this commit we would make sure that we are only overriding functions correctly defined in our hierarchy. With this one, we don't anymore. This is not a big problem though because this is a check that is also enforced by Eolian. So as long as you are using Eolian, you should be fine. Breaks API and ABI! @feature
2016-08-24 07:59:28 -07:00
new_id = (_eo_classes_last_id + 1) | MASK_CLASS_TAG;
_eo_classes_expand();
_eo_classes[_UNMASK_ID(new_id) - 1] = klass;
eina_lock_release(&_efl_class_creation_lock);
Efl object: change the way we set class's functions. This is another follow up to the investigations of T4227. As stated there, in any PIE (a shared library is one), structures, even const ones end up being written to because of dynamic relocation. This means that using static const structures has actually lead to no savings, only waste. Since we never really needed them, using them made things even worse than just having a different API that doesn't save them. Thus, this commit changes the way we set the functions. Instead of passing a pre-populated struct, we now just have an initialiser function where you set the functions. This on its own doesn't significantly reduce the amount of dirty memory pages for a reason I have yet to uncover, though I believe it's done as a misguided compiler optimisation. However, this design is flexible enough so we can change to another one that is quite ugly, but I have already tested and proven that does that. This patch series doesn't include the better improvement (passing everything on the stack as va_args) because the API was too ugly for me to bear, and I would rather first make sure there is no way to force the compiler to do the right thing here. Unfortunately this commit gives up on useless stricter validation. Before this commit we would make sure that we are only overriding functions correctly defined in our hierarchy. With this one, we don't anymore. This is not a big problem though because this is a check that is also enforced by Eolian. So as long as you are using Eolian, you should be fine. Breaks API and ABI! @feature
2016-08-24 07:59:28 -07:00
klass->header.id = new_id;
}
if (!_eo_class_initializer(klass))
{
Efl object: change the way we set class's functions. This is another follow up to the investigations of T4227. As stated there, in any PIE (a shared library is one), structures, even const ones end up being written to because of dynamic relocation. This means that using static const structures has actually lead to no savings, only waste. Since we never really needed them, using them made things even worse than just having a different API that doesn't save them. Thus, this commit changes the way we set the functions. Instead of passing a pre-populated struct, we now just have an initialiser function where you set the functions. This on its own doesn't significantly reduce the amount of dirty memory pages for a reason I have yet to uncover, though I believe it's done as a misguided compiler optimisation. However, this design is flexible enough so we can change to another one that is quite ugly, but I have already tested and proven that does that. This patch series doesn't include the better improvement (passing everything on the stack as va_args) because the API was too ugly for me to bear, and I would rather first make sure there is no way to force the compiler to do the right thing here. Unfortunately this commit gives up on useless stricter validation. Before this commit we would make sure that we are only overriding functions correctly defined in our hierarchy. With this one, we don't anymore. This is not a big problem though because this is a check that is also enforced by Eolian. So as long as you are using Eolian, you should be fine. Breaks API and ABI! @feature
2016-08-24 07:59:28 -07:00
return NULL;
}
Efl object: change the way we set class's functions. This is another follow up to the investigations of T4227. As stated there, in any PIE (a shared library is one), structures, even const ones end up being written to because of dynamic relocation. This means that using static const structures has actually lead to no savings, only waste. Since we never really needed them, using them made things even worse than just having a different API that doesn't save them. Thus, this commit changes the way we set the functions. Instead of passing a pre-populated struct, we now just have an initialiser function where you set the functions. This on its own doesn't significantly reduce the amount of dirty memory pages for a reason I have yet to uncover, though I believe it's done as a misguided compiler optimisation. However, this design is flexible enough so we can change to another one that is quite ugly, but I have already tested and proven that does that. This patch series doesn't include the better improvement (passing everything on the stack as va_args) because the API was too ugly for me to bear, and I would rather first make sure there is no way to force the compiler to do the right thing here. Unfortunately this commit gives up on useless stricter validation. Before this commit we would make sure that we are only overriding functions correctly defined in our hierarchy. With this one, we don't anymore. This is not a big problem though because this is a check that is also enforced by Eolian. So as long as you are using Eolian, you should be fine. Breaks API and ABI! @feature
2016-08-24 07:59:28 -07:00
/* If functions haven't been set, invoke it with an empty ops structure. */
if (!klass->functions_set)
{
efl_class_functions_set(_eo_class_id_get(klass), NULL, NULL);
}
_eo_class_constructor(klass);
DBG("Finished building class '%s'", klass->desc->name);
return _eo_class_id_get(klass);
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API Eina_Bool
efl_object_override(Eo *eo_id, const Efl_Object_Ops *ops)
{
EO_OBJ_POINTER_RETURN_VAL(eo_id, obj, EINA_FALSE);
EO_CLASS_POINTER_GOTO(EFL_OBJECT_OVERRIDE_CLASS, klass, err);
if (ops)
{
Eo_Vtable *vtable = obj->opt->vtable;
//copy all the vtable nodes that we are going to change later on
Eina_Bool *hitmap;
if (!vtable)
{
vtable = calloc(1, sizeof(*vtable));
_vtable_init_size(vtable, obj->klass->vtable.size);
_vtable_take_over(vtable, &obj->klass->vtable);
}
hitmap = alloca(vtable->size * sizeof(Eina_Bool));
memset(hitmap, 0, vtable->size);
if (!_eo_class_funcs_set(vtable, ops, obj->klass, klass, EINA_TRUE, obj->klass->class_id, hitmap))
{
ERR("Failed to override functions for %s@%p. All previous "
"overrides have been reset.", obj->klass->desc->name, eo_id);
if (obj->opt->vtable == vtable)
{
EO_OPTIONAL_COW_SET(obj, vtable, NULL);
}
else
{
_vtable_free(vtable, &obj->klass->vtable);
free(vtable);
}
goto err;
}
EO_OPTIONAL_COW_SET(obj, vtable, vtable);
}
else
{
if (obj->opt->vtable)
{
_vtable_free(obj->opt->vtable, &obj->klass->vtable);
EO_OPTIONAL_COW_SET(obj, vtable, NULL);
}
}
EO_OBJ_DONE(eo_id);
return EINA_TRUE;
err:
EO_OBJ_DONE(eo_id);
return EINA_FALSE;
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API Eina_Bool
efl_isa(const Eo *eo_id, const Efl_Class *klass_id)
{
eo - make eo id table TLS private data for thread safety and speed This moved all the eoid tables, eoid lookup caches, generation count information ad eo_isa cache into a TLS segment of memory that is thread private. There is also a shared domain for EO objects that all threads can access, but it has an added cost of a lock. This means objects accessed outside the thread they were created in cannot be accessed by another thread unless they are adopted in temporarily, or create4d with the shared domain active at the time of creation. child objects will use their parent object domain if created with a parent object passed in. If you were accessing EO (EFL) objects across threads before then this will actually now cause your code to fail as it was invalid before to do this as no actual objects were threadsafe in EFL, so this will force things to "fail early". ecore_thread_main_loop_begin() and end() still work as this uses the eo domain adoption features to temporarily adopt a domain during this section and then return it when done. This returns speed back to eo brining the overhead in my tests of lookup for the elm genlist autobounce test in elementary from about 5-7% down to 2.5-2.6%. A steep drop. This does not mean everything is perfect. Still to do are: 1. Tests in the test suite 2. Some API's to help for sending objects from thread to thread 3. Make the eo call cache TLS data to make it also safe 4. Look at other locks in eo and probably move them to TLS data 5. Make eo resolve and call wrappers that call the real method func do recursive mutex wrapping of the given object IF it is a shared object to provide threadsafety transparently for shared objects (but adding some overhead as a result) 6. Test test est, and that is why this commit is going in now for wider testing 7. Decide how to make this work with sending IPC (between threads) 8. Deciding what makes an object sendable (a sendable property in base?) 9. Deciding what makes an object shareable (a sharable property in base?)
2016-09-07 01:53:33 -07:00
Efl_Id_Domain domain;
Eo_Id_Data *data;
Eo_Id_Table_Data *tdata;
Eina_Bool isa = EINA_FALSE;
if (EINA_UNLIKELY(!eo_id)) return EINA_FALSE;
// Everything can add a override to an existing class, which pretty much means, everything is a efl override
// This is required in order to support our debug-profile for the users of efl_override
if (EINA_UNLIKELY(klass_id == EFL_OBJECT_OVERRIDE_CLASS)) return EINA_TRUE;
// Case where we are looking if eo_id is a class that contain klass_id
if (EINA_UNLIKELY(_eo_is_a_class(eo_id)))
{
EO_CLASS_POINTER_GOTO(klass_id, klass, err_class);
EO_CLASS_POINTER_GOTO(eo_id, lookinto, err_class0);
if (EINA_UNLIKELY(lookinto->vtable.size <= klass->class_id))
return EINA_FALSE;
return !!lookinto->vtable.chain[klass->class_id].funcs;
}
eo - make eo id table TLS private data for thread safety and speed This moved all the eoid tables, eoid lookup caches, generation count information ad eo_isa cache into a TLS segment of memory that is thread private. There is also a shared domain for EO objects that all threads can access, but it has an added cost of a lock. This means objects accessed outside the thread they were created in cannot be accessed by another thread unless they are adopted in temporarily, or create4d with the shared domain active at the time of creation. child objects will use their parent object domain if created with a parent object passed in. If you were accessing EO (EFL) objects across threads before then this will actually now cause your code to fail as it was invalid before to do this as no actual objects were threadsafe in EFL, so this will force things to "fail early". ecore_thread_main_loop_begin() and end() still work as this uses the eo domain adoption features to temporarily adopt a domain during this section and then return it when done. This returns speed back to eo brining the overhead in my tests of lookup for the elm genlist autobounce test in elementary from about 5-7% down to 2.5-2.6%. A steep drop. This does not mean everything is perfect. Still to do are: 1. Tests in the test suite 2. Some API's to help for sending objects from thread to thread 3. Make the eo call cache TLS data to make it also safe 4. Look at other locks in eo and probably move them to TLS data 5. Make eo resolve and call wrappers that call the real method func do recursive mutex wrapping of the given object IF it is a shared object to provide threadsafety transparently for shared objects (but adding some overhead as a result) 6. Test test est, and that is why this commit is going in now for wider testing 7. Decide how to make this work with sending IPC (between threads) 8. Deciding what makes an object sendable (a sendable property in base?) 9. Deciding what makes an object shareable (a sharable property in base?)
2016-09-07 01:53:33 -07:00
domain = ((Eo_Id)eo_id >> SHIFT_DOMAIN) & MASK_DOMAIN;
data = _eo_table_data_get();
tdata = _eo_table_data_table_get(data, domain);
if (EINA_UNLIKELY(!tdata)) goto err;
eo - make eo id table TLS private data for thread safety and speed This moved all the eoid tables, eoid lookup caches, generation count information ad eo_isa cache into a TLS segment of memory that is thread private. There is also a shared domain for EO objects that all threads can access, but it has an added cost of a lock. This means objects accessed outside the thread they were created in cannot be accessed by another thread unless they are adopted in temporarily, or create4d with the shared domain active at the time of creation. child objects will use their parent object domain if created with a parent object passed in. If you were accessing EO (EFL) objects across threads before then this will actually now cause your code to fail as it was invalid before to do this as no actual objects were threadsafe in EFL, so this will force things to "fail early". ecore_thread_main_loop_begin() and end() still work as this uses the eo domain adoption features to temporarily adopt a domain during this section and then return it when done. This returns speed back to eo brining the overhead in my tests of lookup for the elm genlist autobounce test in elementary from about 5-7% down to 2.5-2.6%. A steep drop. This does not mean everything is perfect. Still to do are: 1. Tests in the test suite 2. Some API's to help for sending objects from thread to thread 3. Make the eo call cache TLS data to make it also safe 4. Look at other locks in eo and probably move them to TLS data 5. Make eo resolve and call wrappers that call the real method func do recursive mutex wrapping of the given object IF it is a shared object to provide threadsafety transparently for shared objects (but adding some overhead as a result) 6. Test test est, and that is why this commit is going in now for wider testing 7. Decide how to make this work with sending IPC (between threads) 8. Deciding what makes an object sendable (a sendable property in base?) 9. Deciding what makes an object shareable (a sharable property in base?)
2016-09-07 01:53:33 -07:00
if (EINA_LIKELY(domain != EFL_ID_DOMAIN_SHARED))
{
eo - make eo id table TLS private data for thread safety and speed This moved all the eoid tables, eoid lookup caches, generation count information ad eo_isa cache into a TLS segment of memory that is thread private. There is also a shared domain for EO objects that all threads can access, but it has an added cost of a lock. This means objects accessed outside the thread they were created in cannot be accessed by another thread unless they are adopted in temporarily, or create4d with the shared domain active at the time of creation. child objects will use their parent object domain if created with a parent object passed in. If you were accessing EO (EFL) objects across threads before then this will actually now cause your code to fail as it was invalid before to do this as no actual objects were threadsafe in EFL, so this will force things to "fail early". ecore_thread_main_loop_begin() and end() still work as this uses the eo domain adoption features to temporarily adopt a domain during this section and then return it when done. This returns speed back to eo brining the overhead in my tests of lookup for the elm genlist autobounce test in elementary from about 5-7% down to 2.5-2.6%. A steep drop. This does not mean everything is perfect. Still to do are: 1. Tests in the test suite 2. Some API's to help for sending objects from thread to thread 3. Make the eo call cache TLS data to make it also safe 4. Look at other locks in eo and probably move them to TLS data 5. Make eo resolve and call wrappers that call the real method func do recursive mutex wrapping of the given object IF it is a shared object to provide threadsafety transparently for shared objects (but adding some overhead as a result) 6. Test test est, and that is why this commit is going in now for wider testing 7. Decide how to make this work with sending IPC (between threads) 8. Deciding what makes an object sendable (a sendable property in base?) 9. Deciding what makes an object shareable (a sharable property in base?)
2016-09-07 01:53:33 -07:00
if ((tdata->cache.isa_id == eo_id) &&
(tdata->cache.klass == klass_id))
{
isa = tdata->cache.isa;
return isa;
}
EO_OBJ_POINTER_GOTO(eo_id, obj, err_obj);
EO_CLASS_POINTER_GOTO(klass_id, klass, err_class);
const Eo_Vtable vtable = obj->klass->vtable;
if (EINA_UNLIKELY(vtable.size <= klass->class_id))
return EINA_FALSE;
isa = !!vtable.chain[klass->class_id].funcs;
eo - make eo id table TLS private data for thread safety and speed This moved all the eoid tables, eoid lookup caches, generation count information ad eo_isa cache into a TLS segment of memory that is thread private. There is also a shared domain for EO objects that all threads can access, but it has an added cost of a lock. This means objects accessed outside the thread they were created in cannot be accessed by another thread unless they are adopted in temporarily, or create4d with the shared domain active at the time of creation. child objects will use their parent object domain if created with a parent object passed in. If you were accessing EO (EFL) objects across threads before then this will actually now cause your code to fail as it was invalid before to do this as no actual objects were threadsafe in EFL, so this will force things to "fail early". ecore_thread_main_loop_begin() and end() still work as this uses the eo domain adoption features to temporarily adopt a domain during this section and then return it when done. This returns speed back to eo brining the overhead in my tests of lookup for the elm genlist autobounce test in elementary from about 5-7% down to 2.5-2.6%. A steep drop. This does not mean everything is perfect. Still to do are: 1. Tests in the test suite 2. Some API's to help for sending objects from thread to thread 3. Make the eo call cache TLS data to make it also safe 4. Look at other locks in eo and probably move them to TLS data 5. Make eo resolve and call wrappers that call the real method func do recursive mutex wrapping of the given object IF it is a shared object to provide threadsafety transparently for shared objects (but adding some overhead as a result) 6. Test test est, and that is why this commit is going in now for wider testing 7. Decide how to make this work with sending IPC (between threads) 8. Deciding what makes an object sendable (a sendable property in base?) 9. Deciding what makes an object shareable (a sharable property in base?)
2016-09-07 01:53:33 -07:00
// Caching the result as we do a lot of serial efl_isa due to evas_object_image using it.
tdata->cache.isa_id = eo_id;
tdata->cache.klass = klass_id;
tdata->cache.isa = isa;
eo - make eo id table TLS private data for thread safety and speed This moved all the eoid tables, eoid lookup caches, generation count information ad eo_isa cache into a TLS segment of memory that is thread private. There is also a shared domain for EO objects that all threads can access, but it has an added cost of a lock. This means objects accessed outside the thread they were created in cannot be accessed by another thread unless they are adopted in temporarily, or create4d with the shared domain active at the time of creation. child objects will use their parent object domain if created with a parent object passed in. If you were accessing EO (EFL) objects across threads before then this will actually now cause your code to fail as it was invalid before to do this as no actual objects were threadsafe in EFL, so this will force things to "fail early". ecore_thread_main_loop_begin() and end() still work as this uses the eo domain adoption features to temporarily adopt a domain during this section and then return it when done. This returns speed back to eo brining the overhead in my tests of lookup for the elm genlist autobounce test in elementary from about 5-7% down to 2.5-2.6%. A steep drop. This does not mean everything is perfect. Still to do are: 1. Tests in the test suite 2. Some API's to help for sending objects from thread to thread 3. Make the eo call cache TLS data to make it also safe 4. Look at other locks in eo and probably move them to TLS data 5. Make eo resolve and call wrappers that call the real method func do recursive mutex wrapping of the given object IF it is a shared object to provide threadsafety transparently for shared objects (but adding some overhead as a result) 6. Test test est, and that is why this commit is going in now for wider testing 7. Decide how to make this work with sending IPC (between threads) 8. Deciding what makes an object sendable (a sendable property in base?) 9. Deciding what makes an object shareable (a sharable property in base?)
2016-09-07 01:53:33 -07:00
}
else
{
eina_lock_take(&(_eo_table_data_shared_data->obj_lock));
eo - make eo id table TLS private data for thread safety and speed This moved all the eoid tables, eoid lookup caches, generation count information ad eo_isa cache into a TLS segment of memory that is thread private. There is also a shared domain for EO objects that all threads can access, but it has an added cost of a lock. This means objects accessed outside the thread they were created in cannot be accessed by another thread unless they are adopted in temporarily, or create4d with the shared domain active at the time of creation. child objects will use their parent object domain if created with a parent object passed in. If you were accessing EO (EFL) objects across threads before then this will actually now cause your code to fail as it was invalid before to do this as no actual objects were threadsafe in EFL, so this will force things to "fail early". ecore_thread_main_loop_begin() and end() still work as this uses the eo domain adoption features to temporarily adopt a domain during this section and then return it when done. This returns speed back to eo brining the overhead in my tests of lookup for the elm genlist autobounce test in elementary from about 5-7% down to 2.5-2.6%. A steep drop. This does not mean everything is perfect. Still to do are: 1. Tests in the test suite 2. Some API's to help for sending objects from thread to thread 3. Make the eo call cache TLS data to make it also safe 4. Look at other locks in eo and probably move them to TLS data 5. Make eo resolve and call wrappers that call the real method func do recursive mutex wrapping of the given object IF it is a shared object to provide threadsafety transparently for shared objects (but adding some overhead as a result) 6. Test test est, and that is why this commit is going in now for wider testing 7. Decide how to make this work with sending IPC (between threads) 8. Deciding what makes an object sendable (a sendable property in base?) 9. Deciding what makes an object shareable (a sharable property in base?)
2016-09-07 01:53:33 -07:00
if ((tdata->cache.isa_id == eo_id) &&
(tdata->cache.klass == klass_id))
{
isa = tdata->cache.isa;
// since this is the cache we hope this gets a lot of hits and
// thus lets assume the hit is the mot important thing thus
// put the lock release and return here inline in the l1
// instruction cache hopefully already fetched
eina_lock_release(&(_eo_table_data_shared_data->obj_lock));
return isa;
eo - make eo id table TLS private data for thread safety and speed This moved all the eoid tables, eoid lookup caches, generation count information ad eo_isa cache into a TLS segment of memory that is thread private. There is also a shared domain for EO objects that all threads can access, but it has an added cost of a lock. This means objects accessed outside the thread they were created in cannot be accessed by another thread unless they are adopted in temporarily, or create4d with the shared domain active at the time of creation. child objects will use their parent object domain if created with a parent object passed in. If you were accessing EO (EFL) objects across threads before then this will actually now cause your code to fail as it was invalid before to do this as no actual objects were threadsafe in EFL, so this will force things to "fail early". ecore_thread_main_loop_begin() and end() still work as this uses the eo domain adoption features to temporarily adopt a domain during this section and then return it when done. This returns speed back to eo brining the overhead in my tests of lookup for the elm genlist autobounce test in elementary from about 5-7% down to 2.5-2.6%. A steep drop. This does not mean everything is perfect. Still to do are: 1. Tests in the test suite 2. Some API's to help for sending objects from thread to thread 3. Make the eo call cache TLS data to make it also safe 4. Look at other locks in eo and probably move them to TLS data 5. Make eo resolve and call wrappers that call the real method func do recursive mutex wrapping of the given object IF it is a shared object to provide threadsafety transparently for shared objects (but adding some overhead as a result) 6. Test test est, and that is why this commit is going in now for wider testing 7. Decide how to make this work with sending IPC (between threads) 8. Deciding what makes an object sendable (a sendable property in base?) 9. Deciding what makes an object shareable (a sharable property in base?)
2016-09-07 01:53:33 -07:00
}
EO_OBJ_POINTER_GOTO(eo_id, obj, err_shared_obj);
EO_CLASS_POINTER_GOTO(klass_id, klass, err_shared_class);
if (EINA_UNLIKELY(obj->klass->vtable.size <= klass->class_id))
goto err_vtable;
isa = !!obj->klass->vtable.chain[klass->class_id].funcs;
eo - make eo id table TLS private data for thread safety and speed This moved all the eoid tables, eoid lookup caches, generation count information ad eo_isa cache into a TLS segment of memory that is thread private. There is also a shared domain for EO objects that all threads can access, but it has an added cost of a lock. This means objects accessed outside the thread they were created in cannot be accessed by another thread unless they are adopted in temporarily, or create4d with the shared domain active at the time of creation. child objects will use their parent object domain if created with a parent object passed in. If you were accessing EO (EFL) objects across threads before then this will actually now cause your code to fail as it was invalid before to do this as no actual objects were threadsafe in EFL, so this will force things to "fail early". ecore_thread_main_loop_begin() and end() still work as this uses the eo domain adoption features to temporarily adopt a domain during this section and then return it when done. This returns speed back to eo brining the overhead in my tests of lookup for the elm genlist autobounce test in elementary from about 5-7% down to 2.5-2.6%. A steep drop. This does not mean everything is perfect. Still to do are: 1. Tests in the test suite 2. Some API's to help for sending objects from thread to thread 3. Make the eo call cache TLS data to make it also safe 4. Look at other locks in eo and probably move them to TLS data 5. Make eo resolve and call wrappers that call the real method func do recursive mutex wrapping of the given object IF it is a shared object to provide threadsafety transparently for shared objects (but adding some overhead as a result) 6. Test test est, and that is why this commit is going in now for wider testing 7. Decide how to make this work with sending IPC (between threads) 8. Deciding what makes an object sendable (a sendable property in base?) 9. Deciding what makes an object shareable (a sharable property in base?)
2016-09-07 01:53:33 -07:00
// Caching the result as we do a lot of serial efl_isa due to evas_object_image using it.
tdata->cache.isa_id = eo_id;
tdata->cache.klass = klass_id;
tdata->cache.isa = isa;
err_vtable:
EO_OBJ_DONE(eo_id);
eina_lock_release(&(_eo_table_data_shared_data->obj_lock));
eo - make eo id table TLS private data for thread safety and speed This moved all the eoid tables, eoid lookup caches, generation count information ad eo_isa cache into a TLS segment of memory that is thread private. There is also a shared domain for EO objects that all threads can access, but it has an added cost of a lock. This means objects accessed outside the thread they were created in cannot be accessed by another thread unless they are adopted in temporarily, or create4d with the shared domain active at the time of creation. child objects will use their parent object domain if created with a parent object passed in. If you were accessing EO (EFL) objects across threads before then this will actually now cause your code to fail as it was invalid before to do this as no actual objects were threadsafe in EFL, so this will force things to "fail early". ecore_thread_main_loop_begin() and end() still work as this uses the eo domain adoption features to temporarily adopt a domain during this section and then return it when done. This returns speed back to eo brining the overhead in my tests of lookup for the elm genlist autobounce test in elementary from about 5-7% down to 2.5-2.6%. A steep drop. This does not mean everything is perfect. Still to do are: 1. Tests in the test suite 2. Some API's to help for sending objects from thread to thread 3. Make the eo call cache TLS data to make it also safe 4. Look at other locks in eo and probably move them to TLS data 5. Make eo resolve and call wrappers that call the real method func do recursive mutex wrapping of the given object IF it is a shared object to provide threadsafety transparently for shared objects (but adding some overhead as a result) 6. Test test est, and that is why this commit is going in now for wider testing 7. Decide how to make this work with sending IPC (between threads) 8. Deciding what makes an object sendable (a sendable property in base?) 9. Deciding what makes an object shareable (a sharable property in base?)
2016-09-07 01:53:33 -07:00
}
return isa;
err_shared_class: EINA_COLD
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
_EO_POINTER_ERR(klass_id, "Class (%p) is an invalid ref.", klass_id);
EO_OBJ_DONE(eo_id);
err_shared_obj: EINA_COLD
eina_lock_release(&(_eo_table_data_shared_data->obj_lock));
return EINA_FALSE;
err_class0:
_EO_POINTER_ERR(eo_id, "Class (%p) is an invalid ref.", eo_id);
return EINA_FALSE;
err_class: EINA_COLD
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
_EO_POINTER_ERR(klass_id, "Class (%p) is an invalid ref.", klass_id);
err_obj:
return EINA_FALSE;
err: EINA_COLD
ERR("Object %p is not a valid object in this context: object domain: %d, "
"current domain: %d, local domain: %d, available domains: [%s %s %s %s]."
" Are you trying to access this object from another thread?",
eo_id, (int)domain,
(int)data->domain_stack[data->stack_top], (int)data->local_domain,
(data->tables[0]) ? "0" : " ", (data->tables[1]) ? "1" : " ",
(data->tables[2]) ? "2" : " ", (data->tables[3]) ? "3" : " ");
return EINA_FALSE;
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API Eo *
efl_xref_internal(const char *file, int line, Eo *obj_id, const Eo *ref_obj_id)
{
efl_ref(obj_id);
#ifdef EO_DEBUG
const char *func_name = __func__;
EO_OBJ_POINTER_RETURN_VAL_PROXY(obj_id, obj, obj_id);
Eo_Xref_Node *xref = calloc(1, sizeof(*xref));
xref->ref_obj = ref_obj_id;
xref->file = file;
xref->line = line;
obj->xrefs = eina_inlist_prepend(obj->xrefs, EINA_INLIST_GET(xref));
EO_OBJ_DONE(obj_id);
#else
(void) ref_obj_id;
(void) file;
(void) line;
#endif
return obj_id;
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API void
efl_xunref(Eo *obj_id, const Eo *ref_obj_id)
{
EO_OBJ_POINTER_RETURN(obj_id, obj);
#ifdef EO_DEBUG
Eo_Xref_Node *xref = NULL;
EINA_INLIST_FOREACH(obj->xrefs, xref)
{
Eo: Add reference functions for objects data We want to introduce a new mechanism concerning the data of the Eo objects. The goal is to improve the memory management by defragmenting the memory banks used by the Eo objects. The first phase has been done by raster and consists in allocating the objects into a separate memory region that the one used by malloc. So now, we know where our objects are located. Now, moving objects means moving data of objects. The issue we have here is that a lot of data pointers are stored into data of other objects, e.g Evas Object data into lists for rendering... We need a way to reference the data and eo_data_get doesn't provide us that. So we need to improve the API for data extraction by requesting from the developer if the data will be stored or not. Five functions are supplied: - eo_data_scope_get: no referencing, the data pointer is no more used after exiting the function. - eo_data_ref: reference the data of the object. It means that while the data is referenced, the object cannot be moved. - eo_data_xref: reference the data of the object but for debug purpose, we associate the objects that references. Same behavior as eo_data_ref for non-debug. - eo_data_unref: unreference the data of an object. - eo_data_xunref: unreference the data of an object previously referenced by another object. I deprecated the eo_data_get function. Most of the time, eo_data_scope_get needs to be used. In the next patches, I changed the eo_data_get to the corresponding functions, according to the usage of the data pointer. The next step is to find all the places in the code where the data is stored but not yet referenced. This will be done by: - requesting from every object to unreference all data to other objects. - moving all the objects from one region to another - requesting from every object to rerefenrence the data. - debugging by hunting the segmentation faults and other weird creatures.
2013-03-19 23:56:15 -07:00
if (xref->ref_obj == ref_obj_id)
2013-04-02 17:31:17 -07:00
break;
}
if (xref)
{
obj->xrefs = eina_inlist_remove(obj->xrefs, EINA_INLIST_GET(xref));
eina_freeq_ptr_main_add(xref, free, sizeof(*xref));
}
else
{
Eo: Add reference functions for objects data We want to introduce a new mechanism concerning the data of the Eo objects. The goal is to improve the memory management by defragmenting the memory banks used by the Eo objects. The first phase has been done by raster and consists in allocating the objects into a separate memory region that the one used by malloc. So now, we know where our objects are located. Now, moving objects means moving data of objects. The issue we have here is that a lot of data pointers are stored into data of other objects, e.g Evas Object data into lists for rendering... We need a way to reference the data and eo_data_get doesn't provide us that. So we need to improve the API for data extraction by requesting from the developer if the data will be stored or not. Five functions are supplied: - eo_data_scope_get: no referencing, the data pointer is no more used after exiting the function. - eo_data_ref: reference the data of the object. It means that while the data is referenced, the object cannot be moved. - eo_data_xref: reference the data of the object but for debug purpose, we associate the objects that references. Same behavior as eo_data_ref for non-debug. - eo_data_unref: unreference the data of an object. - eo_data_xunref: unreference the data of an object previously referenced by another object. I deprecated the eo_data_get function. Most of the time, eo_data_scope_get needs to be used. In the next patches, I changed the eo_data_get to the corresponding functions, according to the usage of the data pointer. The next step is to find all the places in the code where the data is stored but not yet referenced. This will be done by: - requesting from every object to unreference all data to other objects. - moving all the objects from one region to another - requesting from every object to rerefenrence the data. - debugging by hunting the segmentation faults and other weird creatures.
2013-03-19 23:56:15 -07:00
ERR("ref_obj (%p) does not reference obj (%p). Aborting unref.", ref_obj_id, obj_id);
EO_OBJ_DONE(obj_id);
return;
}
EO_OBJ_DONE(obj_id);
#else
(void) ref_obj_id;
#endif
efl_unref(obj_id);
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API Eo *
efl_ref(const Eo *obj_id)
{
EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, (Eo *)obj_id);
++(obj->user_refcount);
if (EINA_UNLIKELY(obj->user_refcount == 1))
_efl_ref(obj);
else if (EINA_UNLIKELY(obj->ownership_track && obj->user_refcount == 2))
efl_event_callback_call((Eo *) obj_id, EFL_EVENT_OWNERSHIP_SHARED, NULL);
#ifdef EO_DEBUG
_eo_log_obj_ref_op(obj, EO_REF_OP_REF);
#endif
EO_OBJ_DONE(obj_id);
return (Eo *)obj_id;
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API void
efl_unref(const Eo *obj_id)
{
EO_OBJ_POINTER_RETURN(obj_id, obj);
if (EINA_UNLIKELY((!obj->unref_compensate && obj->user_refcount == 1 && obj->parent) ||
(obj->unref_compensate && obj->user_refcount == 2 && obj->parent)))
{
if (!obj->allow_parent_unref)
CRI("Calling efl_unref instead of efl_del or efl_parent_set(NULL). Temporary fallback in place triggered.");
EO_OBJ_DONE(obj_id);
efl_del(obj_id);
return ;
}
_efl_ref(obj);
if (EINA_UNLIKELY((obj->noref_event) && (!obj->unref_compensate) &&
((obj->user_refcount == 1 && !obj->parent) ||
(obj->user_refcount == 2 && obj->parent))))
{
// We need to report efl_ref_count correctly during EFL_EVENT_NOREF, so fake it
// by adjusting efl_ref_count while inside efl_unref (This should avoid
// infinite loop)
obj->unref_compensate = EINA_TRUE;
// The noref event should happen before any object in the
// tree get affected by the change in refcount.
efl_event_callback_call((Eo *) obj_id, EFL_EVENT_NOREF, NULL);
obj->unref_compensate = EINA_FALSE;
}
--(obj->user_refcount);
#ifdef EO_DEBUG
_eo_log_obj_ref_op(obj, EO_REF_OP_UNREF);
#endif
if (EINA_UNLIKELY((obj->user_refcount <= 0)))
{
if (obj->user_refcount < 0)
{
ERR("Obj:%s@%p. User refcount (%d) < 0. Too many unrefs.",
obj->klass->desc->name, obj_id, obj->user_refcount);
_eo_log_obj_report((Eo_Id)obj_id, EINA_LOG_LEVEL_ERR, __func__, __FILE__, __LINE__);
EO_OBJ_DONE(obj_id);
_efl_unref(obj);
return;
}
_efl_unref(obj);
}
else if (EINA_UNLIKELY(obj->ownership_track && obj->user_refcount == 1))
{
efl_event_callback_call((Eo *) obj_id, EFL_EVENT_OWNERSHIP_UNIQUE, NULL);
}
_apply_auto_unref(obj, obj_id);
_efl_unref(obj);
EO_OBJ_DONE(obj_id);
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API int
efl_ref_count(const Eo *obj_id)
{
EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, 0);
int ref;
ref = obj->user_refcount - (obj->unref_compensate ? 1 : 0);
EO_OBJ_DONE(obj_id);
return ref;
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API int
___efl_ref2_count(const Eo *obj_id)
{
EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, 0);
int ref;
ref = obj->refcount;
EO_OBJ_DONE(obj_id);
return ref;
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API void
___efl_ref2_reset(const Eo *obj_id)
{
EO_OBJ_POINTER_RETURN(obj_id, obj);
obj->refcount = 0;
EO_OBJ_DONE(obj_id);
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API void
efl_del_intercept_set(Eo *obj_id, Efl_Del_Intercept del_intercept_func)
eo del interceptor: add the ability to intercept deletions of eo objects Imagine this. You have an object. You pass this object handle as a message to another thread. Let's say it's not a UI object, so something you might expect to be able to be accessed from multiple threads. In order to keep the object alive you eo_ref() it when placing the message on a queue and eo_unref() it once the message is "done" in the other thread. If the original sender unref()ed the object before the message is done, then the object will be destroyed in the reciever thread. This is bad for objects "expecting" not to be destroyed outside their owning thread. This allows thius situation to be fixed. A constructor in a class of an object can set up a delete interceptor. For example if we have a "loop ownership" class you multi-ple-inherit from/use as a mixin. This class will set up the interceptor to ensure that on destruction if pthread_self() != owning loop thread id, then add object to "delete me" queue on the owning loop and wake it up. the owning loop thread will wake up and then process this queue and delete the queued objects nicely and safely within the "owning context". This can also be used in this same manner to defer deletion within a loop "until later" in the same delete_me queue. You can even use this as a caching mechanism for objects to prevernt their actual destruction and instead place them in a cached area to be picked from at a later date. The uses are many for this and this is a basic building block for future EFL features like generic messages where a message payload could be an eo object and thus the above loop onwership issue can happen and needs fixing. This adds APIs, implementation, documentation (doxy reference) and tests. @feature
2016-03-07 23:57:22 -08:00
{
EO_OBJ_POINTER_RETURN(obj_id, obj);
EO_OPTIONAL_COW_SET(obj, del_intercept, del_intercept_func);
EO_OBJ_DONE(obj_id);
eo del interceptor: add the ability to intercept deletions of eo objects Imagine this. You have an object. You pass this object handle as a message to another thread. Let's say it's not a UI object, so something you might expect to be able to be accessed from multiple threads. In order to keep the object alive you eo_ref() it when placing the message on a queue and eo_unref() it once the message is "done" in the other thread. If the original sender unref()ed the object before the message is done, then the object will be destroyed in the reciever thread. This is bad for objects "expecting" not to be destroyed outside their owning thread. This allows thius situation to be fixed. A constructor in a class of an object can set up a delete interceptor. For example if we have a "loop ownership" class you multi-ple-inherit from/use as a mixin. This class will set up the interceptor to ensure that on destruction if pthread_self() != owning loop thread id, then add object to "delete me" queue on the owning loop and wake it up. the owning loop thread will wake up and then process this queue and delete the queued objects nicely and safely within the "owning context". This can also be used in this same manner to defer deletion within a loop "until later" in the same delete_me queue. You can even use this as a caching mechanism for objects to prevernt their actual destruction and instead place them in a cached area to be picked from at a later date. The uses are many for this and this is a basic building block for future EFL features like generic messages where a message payload could be an eo object and thus the above loop onwership issue can happen and needs fixing. This adds APIs, implementation, documentation (doxy reference) and tests. @feature
2016-03-07 23:57:22 -08:00
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API Efl_Del_Intercept
efl_del_intercept_get(const Eo *obj_id)
eo del interceptor: add the ability to intercept deletions of eo objects Imagine this. You have an object. You pass this object handle as a message to another thread. Let's say it's not a UI object, so something you might expect to be able to be accessed from multiple threads. In order to keep the object alive you eo_ref() it when placing the message on a queue and eo_unref() it once the message is "done" in the other thread. If the original sender unref()ed the object before the message is done, then the object will be destroyed in the reciever thread. This is bad for objects "expecting" not to be destroyed outside their owning thread. This allows thius situation to be fixed. A constructor in a class of an object can set up a delete interceptor. For example if we have a "loop ownership" class you multi-ple-inherit from/use as a mixin. This class will set up the interceptor to ensure that on destruction if pthread_self() != owning loop thread id, then add object to "delete me" queue on the owning loop and wake it up. the owning loop thread will wake up and then process this queue and delete the queued objects nicely and safely within the "owning context". This can also be used in this same manner to defer deletion within a loop "until later" in the same delete_me queue. You can even use this as a caching mechanism for objects to prevernt their actual destruction and instead place them in a cached area to be picked from at a later date. The uses are many for this and this is a basic building block for future EFL features like generic messages where a message payload could be an eo object and thus the above loop onwership issue can happen and needs fixing. This adds APIs, implementation, documentation (doxy reference) and tests. @feature
2016-03-07 23:57:22 -08:00
{
Efl_Del_Intercept func;
EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, NULL);
func = obj->opt->del_intercept;
EO_OBJ_DONE(obj_id);
return func;
eo del interceptor: add the ability to intercept deletions of eo objects Imagine this. You have an object. You pass this object handle as a message to another thread. Let's say it's not a UI object, so something you might expect to be able to be accessed from multiple threads. In order to keep the object alive you eo_ref() it when placing the message on a queue and eo_unref() it once the message is "done" in the other thread. If the original sender unref()ed the object before the message is done, then the object will be destroyed in the reciever thread. This is bad for objects "expecting" not to be destroyed outside their owning thread. This allows thius situation to be fixed. A constructor in a class of an object can set up a delete interceptor. For example if we have a "loop ownership" class you multi-ple-inherit from/use as a mixin. This class will set up the interceptor to ensure that on destruction if pthread_self() != owning loop thread id, then add object to "delete me" queue on the owning loop and wake it up. the owning loop thread will wake up and then process this queue and delete the queued objects nicely and safely within the "owning context". This can also be used in this same manner to defer deletion within a loop "until later" in the same delete_me queue. You can even use this as a caching mechanism for objects to prevernt their actual destruction and instead place them in a cached area to be picked from at a later date. The uses are many for this and this is a basic building block for future EFL features like generic messages where a message payload could be an eo object and thus the above loop onwership issue can happen and needs fixing. This adds APIs, implementation, documentation (doxy reference) and tests. @feature
2016-03-07 23:57:22 -08:00
}
void
_eo_condtor_done(Eo *obj_id)
{
EO_OBJ_POINTER_RETURN(obj_id, obj);
if (obj->condtor_done)
{
ERR("Object %p is already constructed at this point.", obj);
EO_OBJ_DONE(obj_id);
return;
}
obj->condtor_done = EINA_TRUE;
EO_OBJ_DONE(obj_id);
}
static inline void *
_efl_data_scope_safe_get(const _Eo_Object *obj, const _Efl_Class *klass)
{
if (EINA_LIKELY(klass->desc->data_size > 0))
{
return _efl_data_scope_get(obj, klass);
}
return NULL;
}
static inline void *
_efl_data_scope_get(const _Eo_Object *obj, const _Efl_Class *klass)
{
if (EINA_LIKELY(klass->desc->type != EFL_CLASS_TYPE_MIXIN))
return ((char *) obj) + klass->data_offset;
2013-08-09 06:58:55 -07:00
if (EINA_UNLIKELY(klass->desc->data_size == 0))
{
return NULL;
}
2013-08-09 06:58:55 -07:00
else
{
2013-08-09 06:58:55 -07:00
Eo_Extension_Data_Offset *doff_itr = obj->klass->extn_data_off;
2013-08-09 06:58:55 -07:00
if (!doff_itr)
return NULL;
2013-08-09 06:58:55 -07:00
while (doff_itr->klass)
{
2013-08-09 06:58:55 -07:00
if (doff_itr->klass == klass)
return ((char *) obj) + doff_itr->offset;
2013-08-09 06:58:55 -07:00
doff_itr++;
}
}
return NULL;
}
Eo: Add reference functions for objects data We want to introduce a new mechanism concerning the data of the Eo objects. The goal is to improve the memory management by defragmenting the memory banks used by the Eo objects. The first phase has been done by raster and consists in allocating the objects into a separate memory region that the one used by malloc. So now, we know where our objects are located. Now, moving objects means moving data of objects. The issue we have here is that a lot of data pointers are stored into data of other objects, e.g Evas Object data into lists for rendering... We need a way to reference the data and eo_data_get doesn't provide us that. So we need to improve the API for data extraction by requesting from the developer if the data will be stored or not. Five functions are supplied: - eo_data_scope_get: no referencing, the data pointer is no more used after exiting the function. - eo_data_ref: reference the data of the object. It means that while the data is referenced, the object cannot be moved. - eo_data_xref: reference the data of the object but for debug purpose, we associate the objects that references. Same behavior as eo_data_ref for non-debug. - eo_data_unref: unreference the data of an object. - eo_data_xunref: unreference the data of an object previously referenced by another object. I deprecated the eo_data_get function. Most of the time, eo_data_scope_get needs to be used. In the next patches, I changed the eo_data_get to the corresponding functions, according to the usage of the data pointer. The next step is to find all the places in the code where the data is stored but not yet referenced. This will be done by: - requesting from every object to unreference all data to other objects. - moving all the objects from one region to another - requesting from every object to rerefenrence the data. - debugging by hunting the segmentation faults and other weird creatures.
2013-03-19 23:56:15 -07:00
static inline void *
_efl_data_xref_internal(const char *file, int line, _Eo_Object *obj, const _Efl_Class *klass, const _Eo_Object *ref_obj)
Eo: Add reference functions for objects data We want to introduce a new mechanism concerning the data of the Eo objects. The goal is to improve the memory management by defragmenting the memory banks used by the Eo objects. The first phase has been done by raster and consists in allocating the objects into a separate memory region that the one used by malloc. So now, we know where our objects are located. Now, moving objects means moving data of objects. The issue we have here is that a lot of data pointers are stored into data of other objects, e.g Evas Object data into lists for rendering... We need a way to reference the data and eo_data_get doesn't provide us that. So we need to improve the API for data extraction by requesting from the developer if the data will be stored or not. Five functions are supplied: - eo_data_scope_get: no referencing, the data pointer is no more used after exiting the function. - eo_data_ref: reference the data of the object. It means that while the data is referenced, the object cannot be moved. - eo_data_xref: reference the data of the object but for debug purpose, we associate the objects that references. Same behavior as eo_data_ref for non-debug. - eo_data_unref: unreference the data of an object. - eo_data_xunref: unreference the data of an object previously referenced by another object. I deprecated the eo_data_get function. Most of the time, eo_data_scope_get needs to be used. In the next patches, I changed the eo_data_get to the corresponding functions, according to the usage of the data pointer. The next step is to find all the places in the code where the data is stored but not yet referenced. This will be done by: - requesting from every object to unreference all data to other objects. - moving all the objects from one region to another - requesting from every object to rerefenrence the data. - debugging by hunting the segmentation faults and other weird creatures.
2013-03-19 23:56:15 -07:00
{
2013-05-01 11:45:57 -07:00
void *data = NULL;
Eo: Add reference functions for objects data We want to introduce a new mechanism concerning the data of the Eo objects. The goal is to improve the memory management by defragmenting the memory banks used by the Eo objects. The first phase has been done by raster and consists in allocating the objects into a separate memory region that the one used by malloc. So now, we know where our objects are located. Now, moving objects means moving data of objects. The issue we have here is that a lot of data pointers are stored into data of other objects, e.g Evas Object data into lists for rendering... We need a way to reference the data and eo_data_get doesn't provide us that. So we need to improve the API for data extraction by requesting from the developer if the data will be stored or not. Five functions are supplied: - eo_data_scope_get: no referencing, the data pointer is no more used after exiting the function. - eo_data_ref: reference the data of the object. It means that while the data is referenced, the object cannot be moved. - eo_data_xref: reference the data of the object but for debug purpose, we associate the objects that references. Same behavior as eo_data_ref for non-debug. - eo_data_unref: unreference the data of an object. - eo_data_xunref: unreference the data of an object previously referenced by another object. I deprecated the eo_data_get function. Most of the time, eo_data_scope_get needs to be used. In the next patches, I changed the eo_data_get to the corresponding functions, according to the usage of the data pointer. The next step is to find all the places in the code where the data is stored but not yet referenced. This will be done by: - requesting from every object to unreference all data to other objects. - moving all the objects from one region to another - requesting from every object to rerefenrence the data. - debugging by hunting the segmentation faults and other weird creatures.
2013-03-19 23:56:15 -07:00
if (klass != NULL)
{
data = _efl_data_scope_safe_get(obj, klass);
Eo: Add reference functions for objects data We want to introduce a new mechanism concerning the data of the Eo objects. The goal is to improve the memory management by defragmenting the memory banks used by the Eo objects. The first phase has been done by raster and consists in allocating the objects into a separate memory region that the one used by malloc. So now, we know where our objects are located. Now, moving objects means moving data of objects. The issue we have here is that a lot of data pointers are stored into data of other objects, e.g Evas Object data into lists for rendering... We need a way to reference the data and eo_data_get doesn't provide us that. So we need to improve the API for data extraction by requesting from the developer if the data will be stored or not. Five functions are supplied: - eo_data_scope_get: no referencing, the data pointer is no more used after exiting the function. - eo_data_ref: reference the data of the object. It means that while the data is referenced, the object cannot be moved. - eo_data_xref: reference the data of the object but for debug purpose, we associate the objects that references. Same behavior as eo_data_ref for non-debug. - eo_data_unref: unreference the data of an object. - eo_data_xunref: unreference the data of an object previously referenced by another object. I deprecated the eo_data_get function. Most of the time, eo_data_scope_get needs to be used. In the next patches, I changed the eo_data_get to the corresponding functions, according to the usage of the data pointer. The next step is to find all the places in the code where the data is stored but not yet referenced. This will be done by: - requesting from every object to unreference all data to other objects. - moving all the objects from one region to another - requesting from every object to rerefenrence the data. - debugging by hunting the segmentation faults and other weird creatures.
2013-03-19 23:56:15 -07:00
if (data == NULL) return NULL;
}
#ifdef EO_DEBUG
(obj->datarefcount)++;
Eo: Add reference functions for objects data We want to introduce a new mechanism concerning the data of the Eo objects. The goal is to improve the memory management by defragmenting the memory banks used by the Eo objects. The first phase has been done by raster and consists in allocating the objects into a separate memory region that the one used by malloc. So now, we know where our objects are located. Now, moving objects means moving data of objects. The issue we have here is that a lot of data pointers are stored into data of other objects, e.g Evas Object data into lists for rendering... We need a way to reference the data and eo_data_get doesn't provide us that. So we need to improve the API for data extraction by requesting from the developer if the data will be stored or not. Five functions are supplied: - eo_data_scope_get: no referencing, the data pointer is no more used after exiting the function. - eo_data_ref: reference the data of the object. It means that while the data is referenced, the object cannot be moved. - eo_data_xref: reference the data of the object but for debug purpose, we associate the objects that references. Same behavior as eo_data_ref for non-debug. - eo_data_unref: unreference the data of an object. - eo_data_xunref: unreference the data of an object previously referenced by another object. I deprecated the eo_data_get function. Most of the time, eo_data_scope_get needs to be used. In the next patches, I changed the eo_data_get to the corresponding functions, according to the usage of the data pointer. The next step is to find all the places in the code where the data is stored but not yet referenced. This will be done by: - requesting from every object to unreference all data to other objects. - moving all the objects from one region to another - requesting from every object to rerefenrence the data. - debugging by hunting the segmentation faults and other weird creatures.
2013-03-19 23:56:15 -07:00
Eo_Xref_Node *xref = calloc(1, sizeof(*xref));
xref->ref_obj = _eo_obj_id_get(ref_obj);
xref->data_klass = klass ? klass->desc->name : NULL;
Eo: Add reference functions for objects data We want to introduce a new mechanism concerning the data of the Eo objects. The goal is to improve the memory management by defragmenting the memory banks used by the Eo objects. The first phase has been done by raster and consists in allocating the objects into a separate memory region that the one used by malloc. So now, we know where our objects are located. Now, moving objects means moving data of objects. The issue we have here is that a lot of data pointers are stored into data of other objects, e.g Evas Object data into lists for rendering... We need a way to reference the data and eo_data_get doesn't provide us that. So we need to improve the API for data extraction by requesting from the developer if the data will be stored or not. Five functions are supplied: - eo_data_scope_get: no referencing, the data pointer is no more used after exiting the function. - eo_data_ref: reference the data of the object. It means that while the data is referenced, the object cannot be moved. - eo_data_xref: reference the data of the object but for debug purpose, we associate the objects that references. Same behavior as eo_data_ref for non-debug. - eo_data_unref: unreference the data of an object. - eo_data_xunref: unreference the data of an object previously referenced by another object. I deprecated the eo_data_get function. Most of the time, eo_data_scope_get needs to be used. In the next patches, I changed the eo_data_get to the corresponding functions, according to the usage of the data pointer. The next step is to find all the places in the code where the data is stored but not yet referenced. This will be done by: - requesting from every object to unreference all data to other objects. - moving all the objects from one region to another - requesting from every object to rerefenrence the data. - debugging by hunting the segmentation faults and other weird creatures.
2013-03-19 23:56:15 -07:00
xref->file = file;
xref->line = line;
obj->data_xrefs = eina_inlist_prepend(obj->data_xrefs, EINA_INLIST_GET(xref));
#else
(void) ref_obj;
(void) file;
(void) line;
#endif
return data;
}
static inline void
_efl_data_xunref_internal(_Eo_Object *obj EINA_UNUSED, void *data EINA_UNUSED, const _Eo_Object *ref_obj EINA_UNUSED)
Eo: Add reference functions for objects data We want to introduce a new mechanism concerning the data of the Eo objects. The goal is to improve the memory management by defragmenting the memory banks used by the Eo objects. The first phase has been done by raster and consists in allocating the objects into a separate memory region that the one used by malloc. So now, we know where our objects are located. Now, moving objects means moving data of objects. The issue we have here is that a lot of data pointers are stored into data of other objects, e.g Evas Object data into lists for rendering... We need a way to reference the data and eo_data_get doesn't provide us that. So we need to improve the API for data extraction by requesting from the developer if the data will be stored or not. Five functions are supplied: - eo_data_scope_get: no referencing, the data pointer is no more used after exiting the function. - eo_data_ref: reference the data of the object. It means that while the data is referenced, the object cannot be moved. - eo_data_xref: reference the data of the object but for debug purpose, we associate the objects that references. Same behavior as eo_data_ref for non-debug. - eo_data_unref: unreference the data of an object. - eo_data_xunref: unreference the data of an object previously referenced by another object. I deprecated the eo_data_get function. Most of the time, eo_data_scope_get needs to be used. In the next patches, I changed the eo_data_get to the corresponding functions, according to the usage of the data pointer. The next step is to find all the places in the code where the data is stored but not yet referenced. This will be done by: - requesting from every object to unreference all data to other objects. - moving all the objects from one region to another - requesting from every object to rerefenrence the data. - debugging by hunting the segmentation faults and other weird creatures.
2013-03-19 23:56:15 -07:00
{
#ifdef EO_DEBUG
const _Efl_Class *klass = obj->klass;
Eo_Xref_Node *xref = NULL;
2013-09-23 02:07:07 -07:00
Eina_Bool in_range = (((char *)data >= (((char *) obj) + _eo_sz)) &&
((char *)data < (((char *) obj) + klass->obj_size)));
Eo: Add reference functions for objects data We want to introduce a new mechanism concerning the data of the Eo objects. The goal is to improve the memory management by defragmenting the memory banks used by the Eo objects. The first phase has been done by raster and consists in allocating the objects into a separate memory region that the one used by malloc. So now, we know where our objects are located. Now, moving objects means moving data of objects. The issue we have here is that a lot of data pointers are stored into data of other objects, e.g Evas Object data into lists for rendering... We need a way to reference the data and eo_data_get doesn't provide us that. So we need to improve the API for data extraction by requesting from the developer if the data will be stored or not. Five functions are supplied: - eo_data_scope_get: no referencing, the data pointer is no more used after exiting the function. - eo_data_ref: reference the data of the object. It means that while the data is referenced, the object cannot be moved. - eo_data_xref: reference the data of the object but for debug purpose, we associate the objects that references. Same behavior as eo_data_ref for non-debug. - eo_data_unref: unreference the data of an object. - eo_data_xunref: unreference the data of an object previously referenced by another object. I deprecated the eo_data_get function. Most of the time, eo_data_scope_get needs to be used. In the next patches, I changed the eo_data_get to the corresponding functions, according to the usage of the data pointer. The next step is to find all the places in the code where the data is stored but not yet referenced. This will be done by: - requesting from every object to unreference all data to other objects. - moving all the objects from one region to another - requesting from every object to rerefenrence the data. - debugging by hunting the segmentation faults and other weird creatures.
2013-03-19 23:56:15 -07:00
if (!in_range)
{
ERR("Data %p is not in the data range of the object %p (%s).",
data, _eo_obj_id_get(obj), obj->klass->desc->name);
Eo: Add reference functions for objects data We want to introduce a new mechanism concerning the data of the Eo objects. The goal is to improve the memory management by defragmenting the memory banks used by the Eo objects. The first phase has been done by raster and consists in allocating the objects into a separate memory region that the one used by malloc. So now, we know where our objects are located. Now, moving objects means moving data of objects. The issue we have here is that a lot of data pointers are stored into data of other objects, e.g Evas Object data into lists for rendering... We need a way to reference the data and eo_data_get doesn't provide us that. So we need to improve the API for data extraction by requesting from the developer if the data will be stored or not. Five functions are supplied: - eo_data_scope_get: no referencing, the data pointer is no more used after exiting the function. - eo_data_ref: reference the data of the object. It means that while the data is referenced, the object cannot be moved. - eo_data_xref: reference the data of the object but for debug purpose, we associate the objects that references. Same behavior as eo_data_ref for non-debug. - eo_data_unref: unreference the data of an object. - eo_data_xunref: unreference the data of an object previously referenced by another object. I deprecated the eo_data_get function. Most of the time, eo_data_scope_get needs to be used. In the next patches, I changed the eo_data_get to the corresponding functions, according to the usage of the data pointer. The next step is to find all the places in the code where the data is stored but not yet referenced. This will be done by: - requesting from every object to unreference all data to other objects. - moving all the objects from one region to another - requesting from every object to rerefenrence the data. - debugging by hunting the segmentation faults and other weird creatures.
2013-03-19 23:56:15 -07:00
}
if (obj->datarefcount == 0)
{
ERR("Data for object %p (%s) is already not referenced.",
_eo_obj_id_get(obj), obj->klass->desc->name);
Eo: Add reference functions for objects data We want to introduce a new mechanism concerning the data of the Eo objects. The goal is to improve the memory management by defragmenting the memory banks used by the Eo objects. The first phase has been done by raster and consists in allocating the objects into a separate memory region that the one used by malloc. So now, we know where our objects are located. Now, moving objects means moving data of objects. The issue we have here is that a lot of data pointers are stored into data of other objects, e.g Evas Object data into lists for rendering... We need a way to reference the data and eo_data_get doesn't provide us that. So we need to improve the API for data extraction by requesting from the developer if the data will be stored or not. Five functions are supplied: - eo_data_scope_get: no referencing, the data pointer is no more used after exiting the function. - eo_data_ref: reference the data of the object. It means that while the data is referenced, the object cannot be moved. - eo_data_xref: reference the data of the object but for debug purpose, we associate the objects that references. Same behavior as eo_data_ref for non-debug. - eo_data_unref: unreference the data of an object. - eo_data_xunref: unreference the data of an object previously referenced by another object. I deprecated the eo_data_get function. Most of the time, eo_data_scope_get needs to be used. In the next patches, I changed the eo_data_get to the corresponding functions, according to the usage of the data pointer. The next step is to find all the places in the code where the data is stored but not yet referenced. This will be done by: - requesting from every object to unreference all data to other objects. - moving all the objects from one region to another - requesting from every object to rerefenrence the data. - debugging by hunting the segmentation faults and other weird creatures.
2013-03-19 23:56:15 -07:00
}
else
{
(obj->datarefcount)--;
}
EINA_INLIST_FOREACH(obj->data_xrefs, xref)
{
if (xref->ref_obj == _eo_obj_id_get(ref_obj))
Eo: Add reference functions for objects data We want to introduce a new mechanism concerning the data of the Eo objects. The goal is to improve the memory management by defragmenting the memory banks used by the Eo objects. The first phase has been done by raster and consists in allocating the objects into a separate memory region that the one used by malloc. So now, we know where our objects are located. Now, moving objects means moving data of objects. The issue we have here is that a lot of data pointers are stored into data of other objects, e.g Evas Object data into lists for rendering... We need a way to reference the data and eo_data_get doesn't provide us that. So we need to improve the API for data extraction by requesting from the developer if the data will be stored or not. Five functions are supplied: - eo_data_scope_get: no referencing, the data pointer is no more used after exiting the function. - eo_data_ref: reference the data of the object. It means that while the data is referenced, the object cannot be moved. - eo_data_xref: reference the data of the object but for debug purpose, we associate the objects that references. Same behavior as eo_data_ref for non-debug. - eo_data_unref: unreference the data of an object. - eo_data_xunref: unreference the data of an object previously referenced by another object. I deprecated the eo_data_get function. Most of the time, eo_data_scope_get needs to be used. In the next patches, I changed the eo_data_get to the corresponding functions, according to the usage of the data pointer. The next step is to find all the places in the code where the data is stored but not yet referenced. This will be done by: - requesting from every object to unreference all data to other objects. - moving all the objects from one region to another - requesting from every object to rerefenrence the data. - debugging by hunting the segmentation faults and other weird creatures.
2013-03-19 23:56:15 -07:00
break;
}
if (xref)
{
obj->data_xrefs = eina_inlist_remove(obj->data_xrefs, EINA_INLIST_GET(xref));
eina_freeq_ptr_main_add(xref, free, sizeof(*xref));
Eo: Add reference functions for objects data We want to introduce a new mechanism concerning the data of the Eo objects. The goal is to improve the memory management by defragmenting the memory banks used by the Eo objects. The first phase has been done by raster and consists in allocating the objects into a separate memory region that the one used by malloc. So now, we know where our objects are located. Now, moving objects means moving data of objects. The issue we have here is that a lot of data pointers are stored into data of other objects, e.g Evas Object data into lists for rendering... We need a way to reference the data and eo_data_get doesn't provide us that. So we need to improve the API for data extraction by requesting from the developer if the data will be stored or not. Five functions are supplied: - eo_data_scope_get: no referencing, the data pointer is no more used after exiting the function. - eo_data_ref: reference the data of the object. It means that while the data is referenced, the object cannot be moved. - eo_data_xref: reference the data of the object but for debug purpose, we associate the objects that references. Same behavior as eo_data_ref for non-debug. - eo_data_unref: unreference the data of an object. - eo_data_xunref: unreference the data of an object previously referenced by another object. I deprecated the eo_data_get function. Most of the time, eo_data_scope_get needs to be used. In the next patches, I changed the eo_data_get to the corresponding functions, according to the usage of the data pointer. The next step is to find all the places in the code where the data is stored but not yet referenced. This will be done by: - requesting from every object to unreference all data to other objects. - moving all the objects from one region to another - requesting from every object to rerefenrence the data. - debugging by hunting the segmentation faults and other weird creatures.
2013-03-19 23:56:15 -07:00
}
else
{
ERR("ref_obj %p (%s) does not reference data %p of obj %p (%s).",
_eo_obj_id_get(ref_obj), ref_obj->klass->desc->name, data,
_eo_obj_id_get(obj), obj->klass->desc->name);
Eo: Add reference functions for objects data We want to introduce a new mechanism concerning the data of the Eo objects. The goal is to improve the memory management by defragmenting the memory banks used by the Eo objects. The first phase has been done by raster and consists in allocating the objects into a separate memory region that the one used by malloc. So now, we know where our objects are located. Now, moving objects means moving data of objects. The issue we have here is that a lot of data pointers are stored into data of other objects, e.g Evas Object data into lists for rendering... We need a way to reference the data and eo_data_get doesn't provide us that. So we need to improve the API for data extraction by requesting from the developer if the data will be stored or not. Five functions are supplied: - eo_data_scope_get: no referencing, the data pointer is no more used after exiting the function. - eo_data_ref: reference the data of the object. It means that while the data is referenced, the object cannot be moved. - eo_data_xref: reference the data of the object but for debug purpose, we associate the objects that references. Same behavior as eo_data_ref for non-debug. - eo_data_unref: unreference the data of an object. - eo_data_xunref: unreference the data of an object previously referenced by another object. I deprecated the eo_data_get function. Most of the time, eo_data_scope_get needs to be used. In the next patches, I changed the eo_data_get to the corresponding functions, according to the usage of the data pointer. The next step is to find all the places in the code where the data is stored but not yet referenced. This will be done by: - requesting from every object to unreference all data to other objects. - moving all the objects from one region to another - requesting from every object to rerefenrence the data. - debugging by hunting the segmentation faults and other weird creatures.
2013-03-19 23:56:15 -07:00
}
#endif
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API void *
efl_data_scope_get(const Eo *obj_id, const Efl_Class *klass_id)
{
void *ret = NULL;
EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, NULL);
EO_CLASS_POINTER_GOTO(klass_id, klass, err_klass);
#ifndef EO_DEBUG
ret = _efl_data_scope_safe_get(obj, klass);
#else
if (_eo_class_mro_has(obj->klass, klass))
{
ret = _efl_data_scope_safe_get(obj, klass);
if (!ret && (klass->desc->data_size == 0))
ERR("Tried getting data of class '%s', but it has none.", klass->desc->name);
}
else
{
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);
}
#endif
err_klass:
EO_OBJ_DONE(obj_id);
return ret;
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API void *
efl_data_scope_safe_get(const Eo *obj_id, const Efl_Class *klass_id)
{
void *ret = NULL;
if (!obj_id) return NULL;
EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, NULL);
EO_CLASS_POINTER_GOTO(klass_id, klass, err_klass);
if (obj->destructed) goto err_klass;
if (_eo_class_mro_has(obj->klass, klass))
{
ret = _efl_data_scope_safe_get(obj, klass);
#ifdef EO_DEBUG
if (!ret && (klass->desc->data_size == 0))
ERR("Tried getting data of class '%s', but it has none.", klass->desc->name);
#endif
}
err_klass:
EO_OBJ_DONE(obj_id);
return ret;
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API void *
efl_data_xref_internal(const char *file, int line, const Eo *obj_id, const Efl_Class *klass_id, const Eo *ref_obj_id)
Eo: Add reference functions for objects data We want to introduce a new mechanism concerning the data of the Eo objects. The goal is to improve the memory management by defragmenting the memory banks used by the Eo objects. The first phase has been done by raster and consists in allocating the objects into a separate memory region that the one used by malloc. So now, we know where our objects are located. Now, moving objects means moving data of objects. The issue we have here is that a lot of data pointers are stored into data of other objects, e.g Evas Object data into lists for rendering... We need a way to reference the data and eo_data_get doesn't provide us that. So we need to improve the API for data extraction by requesting from the developer if the data will be stored or not. Five functions are supplied: - eo_data_scope_get: no referencing, the data pointer is no more used after exiting the function. - eo_data_ref: reference the data of the object. It means that while the data is referenced, the object cannot be moved. - eo_data_xref: reference the data of the object but for debug purpose, we associate the objects that references. Same behavior as eo_data_ref for non-debug. - eo_data_unref: unreference the data of an object. - eo_data_xunref: unreference the data of an object previously referenced by another object. I deprecated the eo_data_get function. Most of the time, eo_data_scope_get needs to be used. In the next patches, I changed the eo_data_get to the corresponding functions, according to the usage of the data pointer. The next step is to find all the places in the code where the data is stored but not yet referenced. This will be done by: - requesting from every object to unreference all data to other objects. - moving all the objects from one region to another - requesting from every object to rerefenrence the data. - debugging by hunting the segmentation faults and other weird creatures.
2013-03-19 23:56:15 -07:00
{
void *ret = NULL;
_Efl_Class *klass = NULL;
const char *func_name = __func__;
EO_OBJ_POINTER_RETURN_VAL_PROXY(obj_id, obj, NULL);
EO_OBJ_POINTER_PROXY(ref_obj_id, ref_obj);
if (ref_obj)
Eo: Add reference functions for objects data We want to introduce a new mechanism concerning the data of the Eo objects. The goal is to improve the memory management by defragmenting the memory banks used by the Eo objects. The first phase has been done by raster and consists in allocating the objects into a separate memory region that the one used by malloc. So now, we know where our objects are located. Now, moving objects means moving data of objects. The issue we have here is that a lot of data pointers are stored into data of other objects, e.g Evas Object data into lists for rendering... We need a way to reference the data and eo_data_get doesn't provide us that. So we need to improve the API for data extraction by requesting from the developer if the data will be stored or not. Five functions are supplied: - eo_data_scope_get: no referencing, the data pointer is no more used after exiting the function. - eo_data_ref: reference the data of the object. It means that while the data is referenced, the object cannot be moved. - eo_data_xref: reference the data of the object but for debug purpose, we associate the objects that references. Same behavior as eo_data_ref for non-debug. - eo_data_unref: unreference the data of an object. - eo_data_xunref: unreference the data of an object previously referenced by another object. I deprecated the eo_data_get function. Most of the time, eo_data_scope_get needs to be used. In the next patches, I changed the eo_data_get to the corresponding functions, according to the usage of the data pointer. The next step is to find all the places in the code where the data is stored but not yet referenced. This will be done by: - requesting from every object to unreference all data to other objects. - moving all the objects from one region to another - requesting from every object to rerefenrence the data. - debugging by hunting the segmentation faults and other weird creatures.
2013-03-19 23:56:15 -07:00
{
if (klass_id)
Eo: Add reference functions for objects data We want to introduce a new mechanism concerning the data of the Eo objects. The goal is to improve the memory management by defragmenting the memory banks used by the Eo objects. The first phase has been done by raster and consists in allocating the objects into a separate memory region that the one used by malloc. So now, we know where our objects are located. Now, moving objects means moving data of objects. The issue we have here is that a lot of data pointers are stored into data of other objects, e.g Evas Object data into lists for rendering... We need a way to reference the data and eo_data_get doesn't provide us that. So we need to improve the API for data extraction by requesting from the developer if the data will be stored or not. Five functions are supplied: - eo_data_scope_get: no referencing, the data pointer is no more used after exiting the function. - eo_data_ref: reference the data of the object. It means that while the data is referenced, the object cannot be moved. - eo_data_xref: reference the data of the object but for debug purpose, we associate the objects that references. Same behavior as eo_data_ref for non-debug. - eo_data_unref: unreference the data of an object. - eo_data_xunref: unreference the data of an object previously referenced by another object. I deprecated the eo_data_get function. Most of the time, eo_data_scope_get needs to be used. In the next patches, I changed the eo_data_get to the corresponding functions, according to the usage of the data pointer. The next step is to find all the places in the code where the data is stored but not yet referenced. This will be done by: - requesting from every object to unreference all data to other objects. - moving all the objects from one region to another - requesting from every object to rerefenrence the data. - debugging by hunting the segmentation faults and other weird creatures.
2013-03-19 23:56:15 -07:00
{
EO_CLASS_POINTER_GOTO_PROXY(klass_id, klass2, err_klass);
klass = klass2;
#ifdef EO_DEBUG
// rare to use goto to keep instruction cache cleaner
if (!_eo_class_mro_has(obj->klass, klass)) goto err_mro;
Eo: Add reference functions for objects data We want to introduce a new mechanism concerning the data of the Eo objects. The goal is to improve the memory management by defragmenting the memory banks used by the Eo objects. The first phase has been done by raster and consists in allocating the objects into a separate memory region that the one used by malloc. So now, we know where our objects are located. Now, moving objects means moving data of objects. The issue we have here is that a lot of data pointers are stored into data of other objects, e.g Evas Object data into lists for rendering... We need a way to reference the data and eo_data_get doesn't provide us that. So we need to improve the API for data extraction by requesting from the developer if the data will be stored or not. Five functions are supplied: - eo_data_scope_get: no referencing, the data pointer is no more used after exiting the function. - eo_data_ref: reference the data of the object. It means that while the data is referenced, the object cannot be moved. - eo_data_xref: reference the data of the object but for debug purpose, we associate the objects that references. Same behavior as eo_data_ref for non-debug. - eo_data_unref: unreference the data of an object. - eo_data_xunref: unreference the data of an object previously referenced by another object. I deprecated the eo_data_get function. Most of the time, eo_data_scope_get needs to be used. In the next patches, I changed the eo_data_get to the corresponding functions, according to the usage of the data pointer. The next step is to find all the places in the code where the data is stored but not yet referenced. This will be done by: - requesting from every object to unreference all data to other objects. - moving all the objects from one region to another - requesting from every object to rerefenrence the data. - debugging by hunting the segmentation faults and other weird creatures.
2013-03-19 23:56:15 -07:00
#endif
}
Eo: Add reference functions for objects data We want to introduce a new mechanism concerning the data of the Eo objects. The goal is to improve the memory management by defragmenting the memory banks used by the Eo objects. The first phase has been done by raster and consists in allocating the objects into a separate memory region that the one used by malloc. So now, we know where our objects are located. Now, moving objects means moving data of objects. The issue we have here is that a lot of data pointers are stored into data of other objects, e.g Evas Object data into lists for rendering... We need a way to reference the data and eo_data_get doesn't provide us that. So we need to improve the API for data extraction by requesting from the developer if the data will be stored or not. Five functions are supplied: - eo_data_scope_get: no referencing, the data pointer is no more used after exiting the function. - eo_data_ref: reference the data of the object. It means that while the data is referenced, the object cannot be moved. - eo_data_xref: reference the data of the object but for debug purpose, we associate the objects that references. Same behavior as eo_data_ref for non-debug. - eo_data_unref: unreference the data of an object. - eo_data_xunref: unreference the data of an object previously referenced by another object. I deprecated the eo_data_get function. Most of the time, eo_data_scope_get needs to be used. In the next patches, I changed the eo_data_get to the corresponding functions, according to the usage of the data pointer. The next step is to find all the places in the code where the data is stored but not yet referenced. This will be done by: - requesting from every object to unreference all data to other objects. - moving all the objects from one region to another - requesting from every object to rerefenrence the data. - debugging by hunting the segmentation faults and other weird creatures.
2013-03-19 23:56:15 -07:00
ret = _efl_data_xref_internal(file, line, obj, klass, ref_obj);
Eo: Add reference functions for objects data We want to introduce a new mechanism concerning the data of the Eo objects. The goal is to improve the memory management by defragmenting the memory banks used by the Eo objects. The first phase has been done by raster and consists in allocating the objects into a separate memory region that the one used by malloc. So now, we know where our objects are located. Now, moving objects means moving data of objects. The issue we have here is that a lot of data pointers are stored into data of other objects, e.g Evas Object data into lists for rendering... We need a way to reference the data and eo_data_get doesn't provide us that. So we need to improve the API for data extraction by requesting from the developer if the data will be stored or not. Five functions are supplied: - eo_data_scope_get: no referencing, the data pointer is no more used after exiting the function. - eo_data_ref: reference the data of the object. It means that while the data is referenced, the object cannot be moved. - eo_data_xref: reference the data of the object but for debug purpose, we associate the objects that references. Same behavior as eo_data_ref for non-debug. - eo_data_unref: unreference the data of an object. - eo_data_xunref: unreference the data of an object previously referenced by another object. I deprecated the eo_data_get function. Most of the time, eo_data_scope_get needs to be used. In the next patches, I changed the eo_data_get to the corresponding functions, according to the usage of the data pointer. The next step is to find all the places in the code where the data is stored but not yet referenced. This will be done by: - requesting from every object to unreference all data to other objects. - moving all the objects from one region to another - requesting from every object to rerefenrence the data. - debugging by hunting the segmentation faults and other weird creatures.
2013-03-19 23:56:15 -07:00
#ifdef EO_DEBUG
// rare to use goto to keep instruction cache cleaner
if (klass && !ret && (klass->desc->data_size == 0)) goto err_ret;
Eo: Add reference functions for objects data We want to introduce a new mechanism concerning the data of the Eo objects. The goal is to improve the memory management by defragmenting the memory banks used by the Eo objects. The first phase has been done by raster and consists in allocating the objects into a separate memory region that the one used by malloc. So now, we know where our objects are located. Now, moving objects means moving data of objects. The issue we have here is that a lot of data pointers are stored into data of other objects, e.g Evas Object data into lists for rendering... We need a way to reference the data and eo_data_get doesn't provide us that. So we need to improve the API for data extraction by requesting from the developer if the data will be stored or not. Five functions are supplied: - eo_data_scope_get: no referencing, the data pointer is no more used after exiting the function. - eo_data_ref: reference the data of the object. It means that while the data is referenced, the object cannot be moved. - eo_data_xref: reference the data of the object but for debug purpose, we associate the objects that references. Same behavior as eo_data_ref for non-debug. - eo_data_unref: unreference the data of an object. - eo_data_xunref: unreference the data of an object previously referenced by another object. I deprecated the eo_data_get function. Most of the time, eo_data_scope_get needs to be used. In the next patches, I changed the eo_data_get to the corresponding functions, according to the usage of the data pointer. The next step is to find all the places in the code where the data is stored but not yet referenced. This will be done by: - requesting from every object to unreference all data to other objects. - moving all the objects from one region to another - requesting from every object to rerefenrence the data. - debugging by hunting the segmentation faults and other weird creatures.
2013-03-19 23:56:15 -07:00
#endif
err_klass:
EO_OBJ_DONE(ref_obj_id);
}
EO_OBJ_DONE(obj_id);
Eo: Add reference functions for objects data We want to introduce a new mechanism concerning the data of the Eo objects. The goal is to improve the memory management by defragmenting the memory banks used by the Eo objects. The first phase has been done by raster and consists in allocating the objects into a separate memory region that the one used by malloc. So now, we know where our objects are located. Now, moving objects means moving data of objects. The issue we have here is that a lot of data pointers are stored into data of other objects, e.g Evas Object data into lists for rendering... We need a way to reference the data and eo_data_get doesn't provide us that. So we need to improve the API for data extraction by requesting from the developer if the data will be stored or not. Five functions are supplied: - eo_data_scope_get: no referencing, the data pointer is no more used after exiting the function. - eo_data_ref: reference the data of the object. It means that while the data is referenced, the object cannot be moved. - eo_data_xref: reference the data of the object but for debug purpose, we associate the objects that references. Same behavior as eo_data_ref for non-debug. - eo_data_unref: unreference the data of an object. - eo_data_xunref: unreference the data of an object previously referenced by another object. I deprecated the eo_data_get function. Most of the time, eo_data_scope_get needs to be used. In the next patches, I changed the eo_data_get to the corresponding functions, according to the usage of the data pointer. The next step is to find all the places in the code where the data is stored but not yet referenced. This will be done by: - requesting from every object to unreference all data to other objects. - moving all the objects from one region to another - requesting from every object to rerefenrence the data. - debugging by hunting the segmentation faults and other weird creatures.
2013-03-19 23:56:15 -07:00
return ret;
#ifdef EO_DEBUG
err_ret:
ERR("Tried getting data of class '%s', but it has none.", klass->desc->name);
goto err;
err_mro:
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);
err:
EO_OBJ_DONE(obj_id);
EO_OBJ_DONE(ref_obj_id);
return NULL;
#endif
Eo: Add reference functions for objects data We want to introduce a new mechanism concerning the data of the Eo objects. The goal is to improve the memory management by defragmenting the memory banks used by the Eo objects. The first phase has been done by raster and consists in allocating the objects into a separate memory region that the one used by malloc. So now, we know where our objects are located. Now, moving objects means moving data of objects. The issue we have here is that a lot of data pointers are stored into data of other objects, e.g Evas Object data into lists for rendering... We need a way to reference the data and eo_data_get doesn't provide us that. So we need to improve the API for data extraction by requesting from the developer if the data will be stored or not. Five functions are supplied: - eo_data_scope_get: no referencing, the data pointer is no more used after exiting the function. - eo_data_ref: reference the data of the object. It means that while the data is referenced, the object cannot be moved. - eo_data_xref: reference the data of the object but for debug purpose, we associate the objects that references. Same behavior as eo_data_ref for non-debug. - eo_data_unref: unreference the data of an object. - eo_data_xunref: unreference the data of an object previously referenced by another object. I deprecated the eo_data_get function. Most of the time, eo_data_scope_get needs to be used. In the next patches, I changed the eo_data_get to the corresponding functions, according to the usage of the data pointer. The next step is to find all the places in the code where the data is stored but not yet referenced. This will be done by: - requesting from every object to unreference all data to other objects. - moving all the objects from one region to another - requesting from every object to rerefenrence the data. - debugging by hunting the segmentation faults and other weird creatures.
2013-03-19 23:56:15 -07:00
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API void
efl_data_xunref_internal(const Eo *obj_id, void *data, const Eo *ref_obj_id)
Eo: Add reference functions for objects data We want to introduce a new mechanism concerning the data of the Eo objects. The goal is to improve the memory management by defragmenting the memory banks used by the Eo objects. The first phase has been done by raster and consists in allocating the objects into a separate memory region that the one used by malloc. So now, we know where our objects are located. Now, moving objects means moving data of objects. The issue we have here is that a lot of data pointers are stored into data of other objects, e.g Evas Object data into lists for rendering... We need a way to reference the data and eo_data_get doesn't provide us that. So we need to improve the API for data extraction by requesting from the developer if the data will be stored or not. Five functions are supplied: - eo_data_scope_get: no referencing, the data pointer is no more used after exiting the function. - eo_data_ref: reference the data of the object. It means that while the data is referenced, the object cannot be moved. - eo_data_xref: reference the data of the object but for debug purpose, we associate the objects that references. Same behavior as eo_data_ref for non-debug. - eo_data_unref: unreference the data of an object. - eo_data_xunref: unreference the data of an object previously referenced by another object. I deprecated the eo_data_get function. Most of the time, eo_data_scope_get needs to be used. In the next patches, I changed the eo_data_get to the corresponding functions, according to the usage of the data pointer. The next step is to find all the places in the code where the data is stored but not yet referenced. This will be done by: - requesting from every object to unreference all data to other objects. - moving all the objects from one region to another - requesting from every object to rerefenrence the data. - debugging by hunting the segmentation faults and other weird creatures.
2013-03-19 23:56:15 -07:00
{
EO_OBJ_POINTER_RETURN(obj_id, obj);
EO_OBJ_POINTER(ref_obj_id, ref_obj);
if (ref_obj)
{
_efl_data_xunref_internal(obj, data, ref_obj);
EO_OBJ_DONE(ref_obj_id);
}
EO_OBJ_DONE(obj_id);
Eo: Add reference functions for objects data We want to introduce a new mechanism concerning the data of the Eo objects. The goal is to improve the memory management by defragmenting the memory banks used by the Eo objects. The first phase has been done by raster and consists in allocating the objects into a separate memory region that the one used by malloc. So now, we know where our objects are located. Now, moving objects means moving data of objects. The issue we have here is that a lot of data pointers are stored into data of other objects, e.g Evas Object data into lists for rendering... We need a way to reference the data and eo_data_get doesn't provide us that. So we need to improve the API for data extraction by requesting from the developer if the data will be stored or not. Five functions are supplied: - eo_data_scope_get: no referencing, the data pointer is no more used after exiting the function. - eo_data_ref: reference the data of the object. It means that while the data is referenced, the object cannot be moved. - eo_data_xref: reference the data of the object but for debug purpose, we associate the objects that references. Same behavior as eo_data_ref for non-debug. - eo_data_unref: unreference the data of an object. - eo_data_xunref: unreference the data of an object previously referenced by another object. I deprecated the eo_data_get function. Most of the time, eo_data_scope_get needs to be used. In the next patches, I changed the eo_data_get to the corresponding functions, according to the usage of the data pointer. The next step is to find all the places in the code where the data is stored but not yet referenced. This will be done by: - requesting from every object to unreference all data to other objects. - moving all the objects from one region to another - requesting from every object to rerefenrence the data. - debugging by hunting the segmentation faults and other weird creatures.
2013-03-19 23:56:15 -07:00
}
eo - make eo id table TLS private data for thread safety and speed This moved all the eoid tables, eoid lookup caches, generation count information ad eo_isa cache into a TLS segment of memory that is thread private. There is also a shared domain for EO objects that all threads can access, but it has an added cost of a lock. This means objects accessed outside the thread they were created in cannot be accessed by another thread unless they are adopted in temporarily, or create4d with the shared domain active at the time of creation. child objects will use their parent object domain if created with a parent object passed in. If you were accessing EO (EFL) objects across threads before then this will actually now cause your code to fail as it was invalid before to do this as no actual objects were threadsafe in EFL, so this will force things to "fail early". ecore_thread_main_loop_begin() and end() still work as this uses the eo domain adoption features to temporarily adopt a domain during this section and then return it when done. This returns speed back to eo brining the overhead in my tests of lookup for the elm genlist autobounce test in elementary from about 5-7% down to 2.5-2.6%. A steep drop. This does not mean everything is perfect. Still to do are: 1. Tests in the test suite 2. Some API's to help for sending objects from thread to thread 3. Make the eo call cache TLS data to make it also safe 4. Look at other locks in eo and probably move them to TLS data 5. Make eo resolve and call wrappers that call the real method func do recursive mutex wrapping of the given object IF it is a shared object to provide threadsafety transparently for shared objects (but adding some overhead as a result) 6. Test test est, and that is why this commit is going in now for wider testing 7. Decide how to make this work with sending IPC (between threads) 8. Deciding what makes an object sendable (a sendable property in base?) 9. Deciding what makes an object shareable (a sharable property in base?)
2016-09-07 01:53:33 -07:00
static void
_eo_table_del_cb(void *in)
{
Eo_Id_Data *data = in;
_eo_free_ids_tables(data);
}
/* FIXME: Support other domains and tables, at the moment only the main
* domain and table.
* This is used by the gdb debug helper script */
Eo_Id_Data *_eo_gdb_main_domain = NULL;
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API Eina_Bool
efl_object_init(void)
{
const char *log_dom = "eo";
if (_efl_object_init_count++ > 0)
2013-04-02 17:31:17 -07:00
return EINA_TRUE;
eina_init();
#if HAVE_VALGRIND
_eo_trash_bypass = RUNNING_ON_VALGRIND;
#endif
_efl_object_main_thread = eina_thread_self();
_eo_sz = EO_ALIGN_SIZE(sizeof(_Eo_Object));
_eo_class_sz = EO_ALIGN_SIZE(sizeof(_Efl_Class));
2013-04-10 19:58:53 -07:00
_eo_classes = NULL;
_eo_classes_last_id = EO_CLASS_IDS_FIRST - 1;
_eo_log_dom = eina_log_domain_register(log_dom, EINA_COLOR_LIGHTBLUE);
if (_eo_log_dom < 0)
{
2014-01-08 02:10:48 -08:00
EINA_LOG_ERR("Could not register log domain: %s.", log_dom);
return EINA_FALSE;
}
if (!eina_lock_recursive_new(&_efl_class_creation_lock))
{
ERR("Could not init lock.");
return EINA_FALSE;
}
if (!eina_spinlock_new(&_ops_storage_lock))
{
ERR("Could not init lock.");
return EINA_FALSE;
}
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
_eo_log_obj_init();
eina_magic_string_static_set(EO_EINA_MAGIC, EO_EINA_MAGIC_STR);
eina_magic_string_static_set(EO_FREED_EINA_MAGIC,
2013-04-02 17:31:17 -07:00
EO_FREED_EINA_MAGIC_STR);
eina_magic_string_static_set(EO_CLASS_EINA_MAGIC,
2013-04-02 17:31:17 -07:00
EO_CLASS_EINA_MAGIC_STR);
#ifndef _WIN32
_ops_storage = eina_hash_pointer_new(NULL);
#else
_ops_storage = eina_hash_string_superfast_new(NULL);
#endif
eo - make eo id table TLS private data for thread safety and speed This moved all the eoid tables, eoid lookup caches, generation count information ad eo_isa cache into a TLS segment of memory that is thread private. There is also a shared domain for EO objects that all threads can access, but it has an added cost of a lock. This means objects accessed outside the thread they were created in cannot be accessed by another thread unless they are adopted in temporarily, or create4d with the shared domain active at the time of creation. child objects will use their parent object domain if created with a parent object passed in. If you were accessing EO (EFL) objects across threads before then this will actually now cause your code to fail as it was invalid before to do this as no actual objects were threadsafe in EFL, so this will force things to "fail early". ecore_thread_main_loop_begin() and end() still work as this uses the eo domain adoption features to temporarily adopt a domain during this section and then return it when done. This returns speed back to eo brining the overhead in my tests of lookup for the elm genlist autobounce test in elementary from about 5-7% down to 2.5-2.6%. A steep drop. This does not mean everything is perfect. Still to do are: 1. Tests in the test suite 2. Some API's to help for sending objects from thread to thread 3. Make the eo call cache TLS data to make it also safe 4. Look at other locks in eo and probably move them to TLS data 5. Make eo resolve and call wrappers that call the real method func do recursive mutex wrapping of the given object IF it is a shared object to provide threadsafety transparently for shared objects (but adding some overhead as a result) 6. Test test est, and that is why this commit is going in now for wider testing 7. Decide how to make this work with sending IPC (between threads) 8. Deciding what makes an object sendable (a sendable property in base?) 9. Deciding what makes an object shareable (a sharable property in base?)
2016-09-07 01:53:33 -07:00
_eo_table_data_shared = _eo_table_data_new(EFL_ID_DOMAIN_SHARED);
if (!_eo_table_data_shared)
{
ERR("Could not allocate shared table data");
eo - make eo id table TLS private data for thread safety and speed This moved all the eoid tables, eoid lookup caches, generation count information ad eo_isa cache into a TLS segment of memory that is thread private. There is also a shared domain for EO objects that all threads can access, but it has an added cost of a lock. This means objects accessed outside the thread they were created in cannot be accessed by another thread unless they are adopted in temporarily, or create4d with the shared domain active at the time of creation. child objects will use their parent object domain if created with a parent object passed in. If you were accessing EO (EFL) objects across threads before then this will actually now cause your code to fail as it was invalid before to do this as no actual objects were threadsafe in EFL, so this will force things to "fail early". ecore_thread_main_loop_begin() and end() still work as this uses the eo domain adoption features to temporarily adopt a domain during this section and then return it when done. This returns speed back to eo brining the overhead in my tests of lookup for the elm genlist autobounce test in elementary from about 5-7% down to 2.5-2.6%. A steep drop. This does not mean everything is perfect. Still to do are: 1. Tests in the test suite 2. Some API's to help for sending objects from thread to thread 3. Make the eo call cache TLS data to make it also safe 4. Look at other locks in eo and probably move them to TLS data 5. Make eo resolve and call wrappers that call the real method func do recursive mutex wrapping of the given object IF it is a shared object to provide threadsafety transparently for shared objects (but adding some overhead as a result) 6. Test test est, and that is why this commit is going in now for wider testing 7. Decide how to make this work with sending IPC (between threads) 8. Deciding what makes an object sendable (a sendable property in base?) 9. Deciding what makes an object shareable (a sharable property in base?)
2016-09-07 01:53:33 -07:00
return EINA_FALSE;
}
_eo_table_data_shared_data = _eo_table_data_shared->tables[EFL_ID_DOMAIN_SHARED];
eo - make eo id table TLS private data for thread safety and speed This moved all the eoid tables, eoid lookup caches, generation count information ad eo_isa cache into a TLS segment of memory that is thread private. There is also a shared domain for EO objects that all threads can access, but it has an added cost of a lock. This means objects accessed outside the thread they were created in cannot be accessed by another thread unless they are adopted in temporarily, or create4d with the shared domain active at the time of creation. child objects will use their parent object domain if created with a parent object passed in. If you were accessing EO (EFL) objects across threads before then this will actually now cause your code to fail as it was invalid before to do this as no actual objects were threadsafe in EFL, so this will force things to "fail early". ecore_thread_main_loop_begin() and end() still work as this uses the eo domain adoption features to temporarily adopt a domain during this section and then return it when done. This returns speed back to eo brining the overhead in my tests of lookup for the elm genlist autobounce test in elementary from about 5-7% down to 2.5-2.6%. A steep drop. This does not mean everything is perfect. Still to do are: 1. Tests in the test suite 2. Some API's to help for sending objects from thread to thread 3. Make the eo call cache TLS data to make it also safe 4. Look at other locks in eo and probably move them to TLS data 5. Make eo resolve and call wrappers that call the real method func do recursive mutex wrapping of the given object IF it is a shared object to provide threadsafety transparently for shared objects (but adding some overhead as a result) 6. Test test est, and that is why this commit is going in now for wider testing 7. Decide how to make this work with sending IPC (between threads) 8. Deciding what makes an object sendable (a sendable property in base?) 9. Deciding what makes an object shareable (a sharable property in base?)
2016-09-07 01:53:33 -07:00
// specially force eoid data to be creanted so we can switch it to domain 0
Eo_Id_Data *data = _eo_table_data_new(EFL_ID_DOMAIN_MAIN);
_eo_gdb_main_domain = data;
eo - make eo id table TLS private data for thread safety and speed This moved all the eoid tables, eoid lookup caches, generation count information ad eo_isa cache into a TLS segment of memory that is thread private. There is also a shared domain for EO objects that all threads can access, but it has an added cost of a lock. This means objects accessed outside the thread they were created in cannot be accessed by another thread unless they are adopted in temporarily, or create4d with the shared domain active at the time of creation. child objects will use their parent object domain if created with a parent object passed in. If you were accessing EO (EFL) objects across threads before then this will actually now cause your code to fail as it was invalid before to do this as no actual objects were threadsafe in EFL, so this will force things to "fail early". ecore_thread_main_loop_begin() and end() still work as this uses the eo domain adoption features to temporarily adopt a domain during this section and then return it when done. This returns speed back to eo brining the overhead in my tests of lookup for the elm genlist autobounce test in elementary from about 5-7% down to 2.5-2.6%. A steep drop. This does not mean everything is perfect. Still to do are: 1. Tests in the test suite 2. Some API's to help for sending objects from thread to thread 3. Make the eo call cache TLS data to make it also safe 4. Look at other locks in eo and probably move them to TLS data 5. Make eo resolve and call wrappers that call the real method func do recursive mutex wrapping of the given object IF it is a shared object to provide threadsafety transparently for shared objects (but adding some overhead as a result) 6. Test test est, and that is why this commit is going in now for wider testing 7. Decide how to make this work with sending IPC (between threads) 8. Deciding what makes an object sendable (a sendable property in base?) 9. Deciding what makes an object shareable (a sharable property in base?)
2016-09-07 01:53:33 -07:00
if (!data)
{
ERR("Could not allocate main table data");
eo - make eo id table TLS private data for thread safety and speed This moved all the eoid tables, eoid lookup caches, generation count information ad eo_isa cache into a TLS segment of memory that is thread private. There is also a shared domain for EO objects that all threads can access, but it has an added cost of a lock. This means objects accessed outside the thread they were created in cannot be accessed by another thread unless they are adopted in temporarily, or create4d with the shared domain active at the time of creation. child objects will use their parent object domain if created with a parent object passed in. If you were accessing EO (EFL) objects across threads before then this will actually now cause your code to fail as it was invalid before to do this as no actual objects were threadsafe in EFL, so this will force things to "fail early". ecore_thread_main_loop_begin() and end() still work as this uses the eo domain adoption features to temporarily adopt a domain during this section and then return it when done. This returns speed back to eo brining the overhead in my tests of lookup for the elm genlist autobounce test in elementary from about 5-7% down to 2.5-2.6%. A steep drop. This does not mean everything is perfect. Still to do are: 1. Tests in the test suite 2. Some API's to help for sending objects from thread to thread 3. Make the eo call cache TLS data to make it also safe 4. Look at other locks in eo and probably move them to TLS data 5. Make eo resolve and call wrappers that call the real method func do recursive mutex wrapping of the given object IF it is a shared object to provide threadsafety transparently for shared objects (but adding some overhead as a result) 6. Test test est, and that is why this commit is going in now for wider testing 7. Decide how to make this work with sending IPC (between threads) 8. Deciding what makes an object sendable (a sendable property in base?) 9. Deciding what makes an object shareable (a sharable property in base?)
2016-09-07 01:53:33 -07:00
return EINA_FALSE;
}
if (!eina_tls_cb_new(&_eo_table_data, _eo_table_del_cb))
{
ERR("Could not allocate TLS for eo domain data");
_eo_table_del_cb(data);
eo - make eo id table TLS private data for thread safety and speed This moved all the eoid tables, eoid lookup caches, generation count information ad eo_isa cache into a TLS segment of memory that is thread private. There is also a shared domain for EO objects that all threads can access, but it has an added cost of a lock. This means objects accessed outside the thread they were created in cannot be accessed by another thread unless they are adopted in temporarily, or create4d with the shared domain active at the time of creation. child objects will use their parent object domain if created with a parent object passed in. If you were accessing EO (EFL) objects across threads before then this will actually now cause your code to fail as it was invalid before to do this as no actual objects were threadsafe in EFL, so this will force things to "fail early". ecore_thread_main_loop_begin() and end() still work as this uses the eo domain adoption features to temporarily adopt a domain during this section and then return it when done. This returns speed back to eo brining the overhead in my tests of lookup for the elm genlist autobounce test in elementary from about 5-7% down to 2.5-2.6%. A steep drop. This does not mean everything is perfect. Still to do are: 1. Tests in the test suite 2. Some API's to help for sending objects from thread to thread 3. Make the eo call cache TLS data to make it also safe 4. Look at other locks in eo and probably move them to TLS data 5. Make eo resolve and call wrappers that call the real method func do recursive mutex wrapping of the given object IF it is a shared object to provide threadsafety transparently for shared objects (but adding some overhead as a result) 6. Test test est, and that is why this commit is going in now for wider testing 7. Decide how to make this work with sending IPC (between threads) 8. Deciding what makes an object sendable (a sendable property in base?) 9. Deciding what makes an object shareable (a sharable property in base?)
2016-09-07 01:53:33 -07:00
return EINA_FALSE;
}
eina_tls_set(_eo_table_data, data);
_efl_object_main_thread = eina_thread_self();
eo - make eo id table TLS private data for thread safety and speed This moved all the eoid tables, eoid lookup caches, generation count information ad eo_isa cache into a TLS segment of memory that is thread private. There is also a shared domain for EO objects that all threads can access, but it has an added cost of a lock. This means objects accessed outside the thread they were created in cannot be accessed by another thread unless they are adopted in temporarily, or create4d with the shared domain active at the time of creation. child objects will use their parent object domain if created with a parent object passed in. If you were accessing EO (EFL) objects across threads before then this will actually now cause your code to fail as it was invalid before to do this as no actual objects were threadsafe in EFL, so this will force things to "fail early". ecore_thread_main_loop_begin() and end() still work as this uses the eo domain adoption features to temporarily adopt a domain during this section and then return it when done. This returns speed back to eo brining the overhead in my tests of lookup for the elm genlist autobounce test in elementary from about 5-7% down to 2.5-2.6%. A steep drop. This does not mean everything is perfect. Still to do are: 1. Tests in the test suite 2. Some API's to help for sending objects from thread to thread 3. Make the eo call cache TLS data to make it also safe 4. Look at other locks in eo and probably move them to TLS data 5. Make eo resolve and call wrappers that call the real method func do recursive mutex wrapping of the given object IF it is a shared object to provide threadsafety transparently for shared objects (but adding some overhead as a result) 6. Test test est, and that is why this commit is going in now for wider testing 7. Decide how to make this work with sending IPC (between threads) 8. Deciding what makes an object sendable (a sendable property in base?) 9. Deciding what makes an object shareable (a sharable property in base?)
2016-09-07 01:53:33 -07:00
efl_object_optional_cow =
eina_cow_add("Efl Object Optional Data", sizeof(Efl_Object_Optional),
64, &efl_object_optional_cow_default, EINA_TRUE);
_efl_add_fallback_init();
2013-03-27 05:42:55 -07:00
eina_log_timing(_eo_log_dom,
2013-04-02 17:31:17 -07:00
EINA_LOG_STATE_STOP,
EINA_LOG_STATE_INIT);
2013-03-27 05:42:55 -07:00
/* bootstrap EFL_CLASS_CLASS */
const Eo *efl_klass = EFL_CLASS_CLASS;
/* bootstrap EFL_OBJECT_CLASS */
const Eo *efl_object = EFL_OBJECT_CLASS;
return efl_klass && efl_object;
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API Eina_Bool
efl_object_shutdown(void)
{
size_t i;
_Efl_Class **cls_itr = _eo_classes + _eo_classes_last_id - 1;
if (--_efl_object_init_count > 0)
2013-04-02 17:31:17 -07:00
return EINA_TRUE;
#ifdef EO_DEBUG
{
Efl_Object *obj;
Eina_Iterator *objects;
objects = eo_objects_iterator_new();
printf("Objects leaked by EO:\n");
printf("class@pointer - user-refcount internal-refcount\n");
EINA_ITERATOR_FOREACH(objects, obj)
{
printf("%s@%p - %d %d \n", efl_class_name_get(obj), obj, efl_ref_count(obj), ___efl_ref2_count(obj));
}
eina_iterator_free(objects);
}
#endif
2013-03-27 05:42:55 -07:00
eina_log_timing(_eo_log_dom,
2013-04-02 17:31:17 -07:00
EINA_LOG_STATE_START,
EINA_LOG_STATE_SHUTDOWN);
2013-03-27 05:42:55 -07:00
_efl_add_fallback_shutdown();
for (i = 0 ; i < _eo_classes_last_id ; i++, cls_itr--)
{
if (*cls_itr)
2013-04-02 17:31:17 -07:00
eo_class_free(*cls_itr);
}
eina_lock_take(&_efl_class_creation_lock);
_eo_classes_release();
eina_lock_release(&_efl_class_creation_lock);
eina_hash_free(_ops_storage);
2017-12-14 08:45:07 -08:00
_ops_storage = NULL;
eina_spinlock_free(&_ops_storage_lock);
eina_lock_free(&_efl_class_creation_lock);
eo - make eo id table TLS private data for thread safety and speed This moved all the eoid tables, eoid lookup caches, generation count information ad eo_isa cache into a TLS segment of memory that is thread private. There is also a shared domain for EO objects that all threads can access, but it has an added cost of a lock. This means objects accessed outside the thread they were created in cannot be accessed by another thread unless they are adopted in temporarily, or create4d with the shared domain active at the time of creation. child objects will use their parent object domain if created with a parent object passed in. If you were accessing EO (EFL) objects across threads before then this will actually now cause your code to fail as it was invalid before to do this as no actual objects were threadsafe in EFL, so this will force things to "fail early". ecore_thread_main_loop_begin() and end() still work as this uses the eo domain adoption features to temporarily adopt a domain during this section and then return it when done. This returns speed back to eo brining the overhead in my tests of lookup for the elm genlist autobounce test in elementary from about 5-7% down to 2.5-2.6%. A steep drop. This does not mean everything is perfect. Still to do are: 1. Tests in the test suite 2. Some API's to help for sending objects from thread to thread 3. Make the eo call cache TLS data to make it also safe 4. Look at other locks in eo and probably move them to TLS data 5. Make eo resolve and call wrappers that call the real method func do recursive mutex wrapping of the given object IF it is a shared object to provide threadsafety transparently for shared objects (but adding some overhead as a result) 6. Test test est, and that is why this commit is going in now for wider testing 7. Decide how to make this work with sending IPC (between threads) 8. Deciding what makes an object sendable (a sendable property in base?) 9. Deciding what makes an object shareable (a sharable property in base?)
2016-09-07 01:53:33 -07:00
_eo_free_ids_tables(_eo_table_data_get());
eina_tls_free(_eo_table_data);
if (_eo_table_data_shared)
{
_eo_free_ids_tables(_eo_table_data_shared);
_eo_table_data_shared = NULL;
_eo_table_data_shared_data = NULL;
eo - make eo id table TLS private data for thread safety and speed This moved all the eoid tables, eoid lookup caches, generation count information ad eo_isa cache into a TLS segment of memory that is thread private. There is also a shared domain for EO objects that all threads can access, but it has an added cost of a lock. This means objects accessed outside the thread they were created in cannot be accessed by another thread unless they are adopted in temporarily, or create4d with the shared domain active at the time of creation. child objects will use their parent object domain if created with a parent object passed in. If you were accessing EO (EFL) objects across threads before then this will actually now cause your code to fail as it was invalid before to do this as no actual objects were threadsafe in EFL, so this will force things to "fail early". ecore_thread_main_loop_begin() and end() still work as this uses the eo domain adoption features to temporarily adopt a domain during this section and then return it when done. This returns speed back to eo brining the overhead in my tests of lookup for the elm genlist autobounce test in elementary from about 5-7% down to 2.5-2.6%. A steep drop. This does not mean everything is perfect. Still to do are: 1. Tests in the test suite 2. Some API's to help for sending objects from thread to thread 3. Make the eo call cache TLS data to make it also safe 4. Look at other locks in eo and probably move them to TLS data 5. Make eo resolve and call wrappers that call the real method func do recursive mutex wrapping of the given object IF it is a shared object to provide threadsafety transparently for shared objects (but adding some overhead as a result) 6. Test test est, and that is why this commit is going in now for wider testing 7. Decide how to make this work with sending IPC (between threads) 8. Deciding what makes an object sendable (a sendable property in base?) 9. Deciding what makes an object shareable (a sharable property in base?)
2016-09-07 01:53:33 -07:00
}
eina_cow_del(efl_object_optional_cow);
efl_object_optional_cow = NULL;
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
_eo_log_obj_shutdown();
eina_log_domain_unregister(_eo_log_dom);
_eo_log_dom = -1;
++_efl_object_init_generation;
eina_shutdown();
return EINA_FALSE;
}
eo - make eo id table TLS private data for thread safety and speed This moved all the eoid tables, eoid lookup caches, generation count information ad eo_isa cache into a TLS segment of memory that is thread private. There is also a shared domain for EO objects that all threads can access, but it has an added cost of a lock. This means objects accessed outside the thread they were created in cannot be accessed by another thread unless they are adopted in temporarily, or create4d with the shared domain active at the time of creation. child objects will use their parent object domain if created with a parent object passed in. If you were accessing EO (EFL) objects across threads before then this will actually now cause your code to fail as it was invalid before to do this as no actual objects were threadsafe in EFL, so this will force things to "fail early". ecore_thread_main_loop_begin() and end() still work as this uses the eo domain adoption features to temporarily adopt a domain during this section and then return it when done. This returns speed back to eo brining the overhead in my tests of lookup for the elm genlist autobounce test in elementary from about 5-7% down to 2.5-2.6%. A steep drop. This does not mean everything is perfect. Still to do are: 1. Tests in the test suite 2. Some API's to help for sending objects from thread to thread 3. Make the eo call cache TLS data to make it also safe 4. Look at other locks in eo and probably move them to TLS data 5. Make eo resolve and call wrappers that call the real method func do recursive mutex wrapping of the given object IF it is a shared object to provide threadsafety transparently for shared objects (but adding some overhead as a result) 6. Test test est, and that is why this commit is going in now for wider testing 7. Decide how to make this work with sending IPC (between threads) 8. Deciding what makes an object sendable (a sendable property in base?) 9. Deciding what makes an object shareable (a sharable property in base?)
2016-09-07 01:53:33 -07:00
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API Efl_Id_Domain
eo - make eo id table TLS private data for thread safety and speed This moved all the eoid tables, eoid lookup caches, generation count information ad eo_isa cache into a TLS segment of memory that is thread private. There is also a shared domain for EO objects that all threads can access, but it has an added cost of a lock. This means objects accessed outside the thread they were created in cannot be accessed by another thread unless they are adopted in temporarily, or create4d with the shared domain active at the time of creation. child objects will use their parent object domain if created with a parent object passed in. If you were accessing EO (EFL) objects across threads before then this will actually now cause your code to fail as it was invalid before to do this as no actual objects were threadsafe in EFL, so this will force things to "fail early". ecore_thread_main_loop_begin() and end() still work as this uses the eo domain adoption features to temporarily adopt a domain during this section and then return it when done. This returns speed back to eo brining the overhead in my tests of lookup for the elm genlist autobounce test in elementary from about 5-7% down to 2.5-2.6%. A steep drop. This does not mean everything is perfect. Still to do are: 1. Tests in the test suite 2. Some API's to help for sending objects from thread to thread 3. Make the eo call cache TLS data to make it also safe 4. Look at other locks in eo and probably move them to TLS data 5. Make eo resolve and call wrappers that call the real method func do recursive mutex wrapping of the given object IF it is a shared object to provide threadsafety transparently for shared objects (but adding some overhead as a result) 6. Test test est, and that is why this commit is going in now for wider testing 7. Decide how to make this work with sending IPC (between threads) 8. Deciding what makes an object sendable (a sendable property in base?) 9. Deciding what makes an object shareable (a sharable property in base?)
2016-09-07 01:53:33 -07:00
efl_domain_get(void)
{
Eo_Id_Data *data = _eo_table_data_get();
return data->local_domain;
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API Efl_Id_Domain
eo - make eo id table TLS private data for thread safety and speed This moved all the eoid tables, eoid lookup caches, generation count information ad eo_isa cache into a TLS segment of memory that is thread private. There is also a shared domain for EO objects that all threads can access, but it has an added cost of a lock. This means objects accessed outside the thread they were created in cannot be accessed by another thread unless they are adopted in temporarily, or create4d with the shared domain active at the time of creation. child objects will use their parent object domain if created with a parent object passed in. If you were accessing EO (EFL) objects across threads before then this will actually now cause your code to fail as it was invalid before to do this as no actual objects were threadsafe in EFL, so this will force things to "fail early". ecore_thread_main_loop_begin() and end() still work as this uses the eo domain adoption features to temporarily adopt a domain during this section and then return it when done. This returns speed back to eo brining the overhead in my tests of lookup for the elm genlist autobounce test in elementary from about 5-7% down to 2.5-2.6%. A steep drop. This does not mean everything is perfect. Still to do are: 1. Tests in the test suite 2. Some API's to help for sending objects from thread to thread 3. Make the eo call cache TLS data to make it also safe 4. Look at other locks in eo and probably move them to TLS data 5. Make eo resolve and call wrappers that call the real method func do recursive mutex wrapping of the given object IF it is a shared object to provide threadsafety transparently for shared objects (but adding some overhead as a result) 6. Test test est, and that is why this commit is going in now for wider testing 7. Decide how to make this work with sending IPC (between threads) 8. Deciding what makes an object sendable (a sendable property in base?) 9. Deciding what makes an object shareable (a sharable property in base?)
2016-09-07 01:53:33 -07:00
efl_domain_current_get(void)
{
Eo_Id_Data *data = _eo_table_data_get();
return data->domain_stack[data->stack_top];
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API Eina_Bool
eo - make eo id table TLS private data for thread safety and speed This moved all the eoid tables, eoid lookup caches, generation count information ad eo_isa cache into a TLS segment of memory that is thread private. There is also a shared domain for EO objects that all threads can access, but it has an added cost of a lock. This means objects accessed outside the thread they were created in cannot be accessed by another thread unless they are adopted in temporarily, or create4d with the shared domain active at the time of creation. child objects will use their parent object domain if created with a parent object passed in. If you were accessing EO (EFL) objects across threads before then this will actually now cause your code to fail as it was invalid before to do this as no actual objects were threadsafe in EFL, so this will force things to "fail early". ecore_thread_main_loop_begin() and end() still work as this uses the eo domain adoption features to temporarily adopt a domain during this section and then return it when done. This returns speed back to eo brining the overhead in my tests of lookup for the elm genlist autobounce test in elementary from about 5-7% down to 2.5-2.6%. A steep drop. This does not mean everything is perfect. Still to do are: 1. Tests in the test suite 2. Some API's to help for sending objects from thread to thread 3. Make the eo call cache TLS data to make it also safe 4. Look at other locks in eo and probably move them to TLS data 5. Make eo resolve and call wrappers that call the real method func do recursive mutex wrapping of the given object IF it is a shared object to provide threadsafety transparently for shared objects (but adding some overhead as a result) 6. Test test est, and that is why this commit is going in now for wider testing 7. Decide how to make this work with sending IPC (between threads) 8. Deciding what makes an object sendable (a sendable property in base?) 9. Deciding what makes an object shareable (a sharable property in base?)
2016-09-07 01:53:33 -07:00
efl_domain_switch(Efl_Id_Domain domain)
{
Eo_Id_Data *data = _eo_table_data_get();
Eo_Id_Data *new_data;
eo - make eo id table TLS private data for thread safety and speed This moved all the eoid tables, eoid lookup caches, generation count information ad eo_isa cache into a TLS segment of memory that is thread private. There is also a shared domain for EO objects that all threads can access, but it has an added cost of a lock. This means objects accessed outside the thread they were created in cannot be accessed by another thread unless they are adopted in temporarily, or create4d with the shared domain active at the time of creation. child objects will use their parent object domain if created with a parent object passed in. If you were accessing EO (EFL) objects across threads before then this will actually now cause your code to fail as it was invalid before to do this as no actual objects were threadsafe in EFL, so this will force things to "fail early". ecore_thread_main_loop_begin() and end() still work as this uses the eo domain adoption features to temporarily adopt a domain during this section and then return it when done. This returns speed back to eo brining the overhead in my tests of lookup for the elm genlist autobounce test in elementary from about 5-7% down to 2.5-2.6%. A steep drop. This does not mean everything is perfect. Still to do are: 1. Tests in the test suite 2. Some API's to help for sending objects from thread to thread 3. Make the eo call cache TLS data to make it also safe 4. Look at other locks in eo and probably move them to TLS data 5. Make eo resolve and call wrappers that call the real method func do recursive mutex wrapping of the given object IF it is a shared object to provide threadsafety transparently for shared objects (but adding some overhead as a result) 6. Test test est, and that is why this commit is going in now for wider testing 7. Decide how to make this work with sending IPC (between threads) 8. Deciding what makes an object sendable (a sendable property in base?) 9. Deciding what makes an object shareable (a sharable property in base?)
2016-09-07 01:53:33 -07:00
if ((domain < EFL_ID_DOMAIN_MAIN) || (domain > EFL_ID_DOMAIN_THREAD) ||
(domain == EFL_ID_DOMAIN_SHARED))
{
ERR("Invalid domain %i being switched to", domain);
return EINA_FALSE;
}
if ((data) && (data->local_domain == domain))
return EINA_TRUE;
new_data = _eo_table_data_new(domain);
if (!new_data)
eo - make eo id table TLS private data for thread safety and speed This moved all the eoid tables, eoid lookup caches, generation count information ad eo_isa cache into a TLS segment of memory that is thread private. There is also a shared domain for EO objects that all threads can access, but it has an added cost of a lock. This means objects accessed outside the thread they were created in cannot be accessed by another thread unless they are adopted in temporarily, or create4d with the shared domain active at the time of creation. child objects will use their parent object domain if created with a parent object passed in. If you were accessing EO (EFL) objects across threads before then this will actually now cause your code to fail as it was invalid before to do this as no actual objects were threadsafe in EFL, so this will force things to "fail early". ecore_thread_main_loop_begin() and end() still work as this uses the eo domain adoption features to temporarily adopt a domain during this section and then return it when done. This returns speed back to eo brining the overhead in my tests of lookup for the elm genlist autobounce test in elementary from about 5-7% down to 2.5-2.6%. A steep drop. This does not mean everything is perfect. Still to do are: 1. Tests in the test suite 2. Some API's to help for sending objects from thread to thread 3. Make the eo call cache TLS data to make it also safe 4. Look at other locks in eo and probably move them to TLS data 5. Make eo resolve and call wrappers that call the real method func do recursive mutex wrapping of the given object IF it is a shared object to provide threadsafety transparently for shared objects (but adding some overhead as a result) 6. Test test est, and that is why this commit is going in now for wider testing 7. Decide how to make this work with sending IPC (between threads) 8. Deciding what makes an object sendable (a sendable property in base?) 9. Deciding what makes an object shareable (a sharable property in base?)
2016-09-07 01:53:33 -07:00
{
ERR("Could not allocate domain %i table data", domain);
return EINA_FALSE;
eo - make eo id table TLS private data for thread safety and speed This moved all the eoid tables, eoid lookup caches, generation count information ad eo_isa cache into a TLS segment of memory that is thread private. There is also a shared domain for EO objects that all threads can access, but it has an added cost of a lock. This means objects accessed outside the thread they were created in cannot be accessed by another thread unless they are adopted in temporarily, or create4d with the shared domain active at the time of creation. child objects will use their parent object domain if created with a parent object passed in. If you were accessing EO (EFL) objects across threads before then this will actually now cause your code to fail as it was invalid before to do this as no actual objects were threadsafe in EFL, so this will force things to "fail early". ecore_thread_main_loop_begin() and end() still work as this uses the eo domain adoption features to temporarily adopt a domain during this section and then return it when done. This returns speed back to eo brining the overhead in my tests of lookup for the elm genlist autobounce test in elementary from about 5-7% down to 2.5-2.6%. A steep drop. This does not mean everything is perfect. Still to do are: 1. Tests in the test suite 2. Some API's to help for sending objects from thread to thread 3. Make the eo call cache TLS data to make it also safe 4. Look at other locks in eo and probably move them to TLS data 5. Make eo resolve and call wrappers that call the real method func do recursive mutex wrapping of the given object IF it is a shared object to provide threadsafety transparently for shared objects (but adding some overhead as a result) 6. Test test est, and that is why this commit is going in now for wider testing 7. Decide how to make this work with sending IPC (between threads) 8. Deciding what makes an object sendable (a sendable property in base?) 9. Deciding what makes an object shareable (a sharable property in base?)
2016-09-07 01:53:33 -07:00
}
if (data) _eo_free_ids_tables(data);
new_data->local_domain = domain;
new_data->domain_stack[new_data->stack_top] = domain;
eina_tls_set(_eo_table_data, new_data);
eo - make eo id table TLS private data for thread safety and speed This moved all the eoid tables, eoid lookup caches, generation count information ad eo_isa cache into a TLS segment of memory that is thread private. There is also a shared domain for EO objects that all threads can access, but it has an added cost of a lock. This means objects accessed outside the thread they were created in cannot be accessed by another thread unless they are adopted in temporarily, or create4d with the shared domain active at the time of creation. child objects will use their parent object domain if created with a parent object passed in. If you were accessing EO (EFL) objects across threads before then this will actually now cause your code to fail as it was invalid before to do this as no actual objects were threadsafe in EFL, so this will force things to "fail early". ecore_thread_main_loop_begin() and end() still work as this uses the eo domain adoption features to temporarily adopt a domain during this section and then return it when done. This returns speed back to eo brining the overhead in my tests of lookup for the elm genlist autobounce test in elementary from about 5-7% down to 2.5-2.6%. A steep drop. This does not mean everything is perfect. Still to do are: 1. Tests in the test suite 2. Some API's to help for sending objects from thread to thread 3. Make the eo call cache TLS data to make it also safe 4. Look at other locks in eo and probably move them to TLS data 5. Make eo resolve and call wrappers that call the real method func do recursive mutex wrapping of the given object IF it is a shared object to provide threadsafety transparently for shared objects (but adding some overhead as a result) 6. Test test est, and that is why this commit is going in now for wider testing 7. Decide how to make this work with sending IPC (between threads) 8. Deciding what makes an object sendable (a sendable property in base?) 9. Deciding what makes an object shareable (a sharable property in base?)
2016-09-07 01:53:33 -07:00
return EINA_TRUE;
}
static inline Eina_Bool
_efl_domain_push(Eo_Id_Data *data, Efl_Id_Domain domain)
{
if (data->stack_top >= (sizeof(data->domain_stack) - 1))
{
ERR("Failed to push domain %i on stack. Out of stack space at %i",
domain, data->stack_top);
return EINA_FALSE;
}
data->stack_top++;
data->domain_stack[data->stack_top] = domain;
return EINA_TRUE;
}
static inline void
_efl_domain_pop(Eo_Id_Data *data)
{
if (data->stack_top > 0) data->stack_top--;
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API Eina_Bool
eo - make eo id table TLS private data for thread safety and speed This moved all the eoid tables, eoid lookup caches, generation count information ad eo_isa cache into a TLS segment of memory that is thread private. There is also a shared domain for EO objects that all threads can access, but it has an added cost of a lock. This means objects accessed outside the thread they were created in cannot be accessed by another thread unless they are adopted in temporarily, or create4d with the shared domain active at the time of creation. child objects will use their parent object domain if created with a parent object passed in. If you were accessing EO (EFL) objects across threads before then this will actually now cause your code to fail as it was invalid before to do this as no actual objects were threadsafe in EFL, so this will force things to "fail early". ecore_thread_main_loop_begin() and end() still work as this uses the eo domain adoption features to temporarily adopt a domain during this section and then return it when done. This returns speed back to eo brining the overhead in my tests of lookup for the elm genlist autobounce test in elementary from about 5-7% down to 2.5-2.6%. A steep drop. This does not mean everything is perfect. Still to do are: 1. Tests in the test suite 2. Some API's to help for sending objects from thread to thread 3. Make the eo call cache TLS data to make it also safe 4. Look at other locks in eo and probably move them to TLS data 5. Make eo resolve and call wrappers that call the real method func do recursive mutex wrapping of the given object IF it is a shared object to provide threadsafety transparently for shared objects (but adding some overhead as a result) 6. Test test est, and that is why this commit is going in now for wider testing 7. Decide how to make this work with sending IPC (between threads) 8. Deciding what makes an object sendable (a sendable property in base?) 9. Deciding what makes an object shareable (a sharable property in base?)
2016-09-07 01:53:33 -07:00
efl_domain_current_push(Efl_Id_Domain domain)
{
Eo_Id_Data *data = _eo_table_data_get();
return _efl_domain_push(data, domain);
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API void
eo - make eo id table TLS private data for thread safety and speed This moved all the eoid tables, eoid lookup caches, generation count information ad eo_isa cache into a TLS segment of memory that is thread private. There is also a shared domain for EO objects that all threads can access, but it has an added cost of a lock. This means objects accessed outside the thread they were created in cannot be accessed by another thread unless they are adopted in temporarily, or create4d with the shared domain active at the time of creation. child objects will use their parent object domain if created with a parent object passed in. If you were accessing EO (EFL) objects across threads before then this will actually now cause your code to fail as it was invalid before to do this as no actual objects were threadsafe in EFL, so this will force things to "fail early". ecore_thread_main_loop_begin() and end() still work as this uses the eo domain adoption features to temporarily adopt a domain during this section and then return it when done. This returns speed back to eo brining the overhead in my tests of lookup for the elm genlist autobounce test in elementary from about 5-7% down to 2.5-2.6%. A steep drop. This does not mean everything is perfect. Still to do are: 1. Tests in the test suite 2. Some API's to help for sending objects from thread to thread 3. Make the eo call cache TLS data to make it also safe 4. Look at other locks in eo and probably move them to TLS data 5. Make eo resolve and call wrappers that call the real method func do recursive mutex wrapping of the given object IF it is a shared object to provide threadsafety transparently for shared objects (but adding some overhead as a result) 6. Test test est, and that is why this commit is going in now for wider testing 7. Decide how to make this work with sending IPC (between threads) 8. Deciding what makes an object sendable (a sendable property in base?) 9. Deciding what makes an object shareable (a sharable property in base?)
2016-09-07 01:53:33 -07:00
efl_domain_current_pop(void)
{
Eo_Id_Data *data = _eo_table_data_get();
_efl_domain_pop(data);
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API Eina_Bool
eo - make eo id table TLS private data for thread safety and speed This moved all the eoid tables, eoid lookup caches, generation count information ad eo_isa cache into a TLS segment of memory that is thread private. There is also a shared domain for EO objects that all threads can access, but it has an added cost of a lock. This means objects accessed outside the thread they were created in cannot be accessed by another thread unless they are adopted in temporarily, or create4d with the shared domain active at the time of creation. child objects will use their parent object domain if created with a parent object passed in. If you were accessing EO (EFL) objects across threads before then this will actually now cause your code to fail as it was invalid before to do this as no actual objects were threadsafe in EFL, so this will force things to "fail early". ecore_thread_main_loop_begin() and end() still work as this uses the eo domain adoption features to temporarily adopt a domain during this section and then return it when done. This returns speed back to eo brining the overhead in my tests of lookup for the elm genlist autobounce test in elementary from about 5-7% down to 2.5-2.6%. A steep drop. This does not mean everything is perfect. Still to do are: 1. Tests in the test suite 2. Some API's to help for sending objects from thread to thread 3. Make the eo call cache TLS data to make it also safe 4. Look at other locks in eo and probably move them to TLS data 5. Make eo resolve and call wrappers that call the real method func do recursive mutex wrapping of the given object IF it is a shared object to provide threadsafety transparently for shared objects (but adding some overhead as a result) 6. Test test est, and that is why this commit is going in now for wider testing 7. Decide how to make this work with sending IPC (between threads) 8. Deciding what makes an object sendable (a sendable property in base?) 9. Deciding what makes an object shareable (a sharable property in base?)
2016-09-07 01:53:33 -07:00
efl_domain_current_set(Efl_Id_Domain domain)
{
Eo_Id_Data *data = _eo_table_data_get();
if ((domain < EFL_ID_DOMAIN_MAIN) || (domain > EFL_ID_DOMAIN_THREAD))
{
ERR("Invalid domain %i being set", domain);
return EINA_FALSE;
}
data->domain_stack[data->stack_top] = domain;
return EINA_TRUE;
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API Efl_Domain_Data *
eo - make eo id table TLS private data for thread safety and speed This moved all the eoid tables, eoid lookup caches, generation count information ad eo_isa cache into a TLS segment of memory that is thread private. There is also a shared domain for EO objects that all threads can access, but it has an added cost of a lock. This means objects accessed outside the thread they were created in cannot be accessed by another thread unless they are adopted in temporarily, or create4d with the shared domain active at the time of creation. child objects will use their parent object domain if created with a parent object passed in. If you were accessing EO (EFL) objects across threads before then this will actually now cause your code to fail as it was invalid before to do this as no actual objects were threadsafe in EFL, so this will force things to "fail early". ecore_thread_main_loop_begin() and end() still work as this uses the eo domain adoption features to temporarily adopt a domain during this section and then return it when done. This returns speed back to eo brining the overhead in my tests of lookup for the elm genlist autobounce test in elementary from about 5-7% down to 2.5-2.6%. A steep drop. This does not mean everything is perfect. Still to do are: 1. Tests in the test suite 2. Some API's to help for sending objects from thread to thread 3. Make the eo call cache TLS data to make it also safe 4. Look at other locks in eo and probably move them to TLS data 5. Make eo resolve and call wrappers that call the real method func do recursive mutex wrapping of the given object IF it is a shared object to provide threadsafety transparently for shared objects (but adding some overhead as a result) 6. Test test est, and that is why this commit is going in now for wider testing 7. Decide how to make this work with sending IPC (between threads) 8. Deciding what makes an object sendable (a sendable property in base?) 9. Deciding what makes an object shareable (a sharable property in base?)
2016-09-07 01:53:33 -07:00
efl_domain_data_get(void)
{
Eo_Id_Data *data = _eo_table_data_get();
return (Efl_Domain_Data *)data;
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API Efl_Id_Domain
eo - make eo id table TLS private data for thread safety and speed This moved all the eoid tables, eoid lookup caches, generation count information ad eo_isa cache into a TLS segment of memory that is thread private. There is also a shared domain for EO objects that all threads can access, but it has an added cost of a lock. This means objects accessed outside the thread they were created in cannot be accessed by another thread unless they are adopted in temporarily, or create4d with the shared domain active at the time of creation. child objects will use their parent object domain if created with a parent object passed in. If you were accessing EO (EFL) objects across threads before then this will actually now cause your code to fail as it was invalid before to do this as no actual objects were threadsafe in EFL, so this will force things to "fail early". ecore_thread_main_loop_begin() and end() still work as this uses the eo domain adoption features to temporarily adopt a domain during this section and then return it when done. This returns speed back to eo brining the overhead in my tests of lookup for the elm genlist autobounce test in elementary from about 5-7% down to 2.5-2.6%. A steep drop. This does not mean everything is perfect. Still to do are: 1. Tests in the test suite 2. Some API's to help for sending objects from thread to thread 3. Make the eo call cache TLS data to make it also safe 4. Look at other locks in eo and probably move them to TLS data 5. Make eo resolve and call wrappers that call the real method func do recursive mutex wrapping of the given object IF it is a shared object to provide threadsafety transparently for shared objects (but adding some overhead as a result) 6. Test test est, and that is why this commit is going in now for wider testing 7. Decide how to make this work with sending IPC (between threads) 8. Deciding what makes an object sendable (a sendable property in base?) 9. Deciding what makes an object shareable (a sharable property in base?)
2016-09-07 01:53:33 -07:00
efl_domain_data_adopt(Efl_Domain_Data *data_in)
{
Eo_Id_Data *data = _eo_table_data_get();
Eo_Id_Data *data_foreign = (Eo_Id_Data *)data_in;
if (!data_foreign)
{
ERR("Trying to adopt NULL domain data [data=%p in=%p]", data, data_in);
eo - make eo id table TLS private data for thread safety and speed This moved all the eoid tables, eoid lookup caches, generation count information ad eo_isa cache into a TLS segment of memory that is thread private. There is also a shared domain for EO objects that all threads can access, but it has an added cost of a lock. This means objects accessed outside the thread they were created in cannot be accessed by another thread unless they are adopted in temporarily, or create4d with the shared domain active at the time of creation. child objects will use their parent object domain if created with a parent object passed in. If you were accessing EO (EFL) objects across threads before then this will actually now cause your code to fail as it was invalid before to do this as no actual objects were threadsafe in EFL, so this will force things to "fail early". ecore_thread_main_loop_begin() and end() still work as this uses the eo domain adoption features to temporarily adopt a domain during this section and then return it when done. This returns speed back to eo brining the overhead in my tests of lookup for the elm genlist autobounce test in elementary from about 5-7% down to 2.5-2.6%. A steep drop. This does not mean everything is perfect. Still to do are: 1. Tests in the test suite 2. Some API's to help for sending objects from thread to thread 3. Make the eo call cache TLS data to make it also safe 4. Look at other locks in eo and probably move them to TLS data 5. Make eo resolve and call wrappers that call the real method func do recursive mutex wrapping of the given object IF it is a shared object to provide threadsafety transparently for shared objects (but adding some overhead as a result) 6. Test test est, and that is why this commit is going in now for wider testing 7. Decide how to make this work with sending IPC (between threads) 8. Deciding what makes an object sendable (a sendable property in base?) 9. Deciding what makes an object shareable (a sharable property in base?)
2016-09-07 01:53:33 -07:00
return EFL_ID_DOMAIN_INVALID;
}
if (data_foreign->local_domain == data->local_domain)
{
ERR("Trying to adopt EO ID domain %i, is the same as the local %i [data=%p in=%p foreign=%p]",
data_foreign->local_domain, data->local_domain, data, data_in, data_foreign);
eo - make eo id table TLS private data for thread safety and speed This moved all the eoid tables, eoid lookup caches, generation count information ad eo_isa cache into a TLS segment of memory that is thread private. There is also a shared domain for EO objects that all threads can access, but it has an added cost of a lock. This means objects accessed outside the thread they were created in cannot be accessed by another thread unless they are adopted in temporarily, or create4d with the shared domain active at the time of creation. child objects will use their parent object domain if created with a parent object passed in. If you were accessing EO (EFL) objects across threads before then this will actually now cause your code to fail as it was invalid before to do this as no actual objects were threadsafe in EFL, so this will force things to "fail early". ecore_thread_main_loop_begin() and end() still work as this uses the eo domain adoption features to temporarily adopt a domain during this section and then return it when done. This returns speed back to eo brining the overhead in my tests of lookup for the elm genlist autobounce test in elementary from about 5-7% down to 2.5-2.6%. A steep drop. This does not mean everything is perfect. Still to do are: 1. Tests in the test suite 2. Some API's to help for sending objects from thread to thread 3. Make the eo call cache TLS data to make it also safe 4. Look at other locks in eo and probably move them to TLS data 5. Make eo resolve and call wrappers that call the real method func do recursive mutex wrapping of the given object IF it is a shared object to provide threadsafety transparently for shared objects (but adding some overhead as a result) 6. Test test est, and that is why this commit is going in now for wider testing 7. Decide how to make this work with sending IPC (between threads) 8. Deciding what makes an object sendable (a sendable property in base?) 9. Deciding what makes an object shareable (a sharable property in base?)
2016-09-07 01:53:33 -07:00
return EFL_ID_DOMAIN_INVALID;
}
if (data->tables[data_foreign->local_domain])
{
ERR("Trying to adopt an already adopted domain [data=%p in=%p foreign=%p]", data, data_in, data_foreign);
eo - make eo id table TLS private data for thread safety and speed This moved all the eoid tables, eoid lookup caches, generation count information ad eo_isa cache into a TLS segment of memory that is thread private. There is also a shared domain for EO objects that all threads can access, but it has an added cost of a lock. This means objects accessed outside the thread they were created in cannot be accessed by another thread unless they are adopted in temporarily, or create4d with the shared domain active at the time of creation. child objects will use their parent object domain if created with a parent object passed in. If you were accessing EO (EFL) objects across threads before then this will actually now cause your code to fail as it was invalid before to do this as no actual objects were threadsafe in EFL, so this will force things to "fail early". ecore_thread_main_loop_begin() and end() still work as this uses the eo domain adoption features to temporarily adopt a domain during this section and then return it when done. This returns speed back to eo brining the overhead in my tests of lookup for the elm genlist autobounce test in elementary from about 5-7% down to 2.5-2.6%. A steep drop. This does not mean everything is perfect. Still to do are: 1. Tests in the test suite 2. Some API's to help for sending objects from thread to thread 3. Make the eo call cache TLS data to make it also safe 4. Look at other locks in eo and probably move them to TLS data 5. Make eo resolve and call wrappers that call the real method func do recursive mutex wrapping of the given object IF it is a shared object to provide threadsafety transparently for shared objects (but adding some overhead as a result) 6. Test test est, and that is why this commit is going in now for wider testing 7. Decide how to make this work with sending IPC (between threads) 8. Deciding what makes an object sendable (a sendable property in base?) 9. Deciding what makes an object shareable (a sharable property in base?)
2016-09-07 01:53:33 -07:00
return EFL_ID_DOMAIN_INVALID;
}
data->tables[data_foreign->local_domain] =
data_foreign->tables[data_foreign->local_domain];
_efl_domain_push(data, data_foreign->local_domain);
return data->domain_stack[data->stack_top];
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API Eina_Bool
eo - make eo id table TLS private data for thread safety and speed This moved all the eoid tables, eoid lookup caches, generation count information ad eo_isa cache into a TLS segment of memory that is thread private. There is also a shared domain for EO objects that all threads can access, but it has an added cost of a lock. This means objects accessed outside the thread they were created in cannot be accessed by another thread unless they are adopted in temporarily, or create4d with the shared domain active at the time of creation. child objects will use their parent object domain if created with a parent object passed in. If you were accessing EO (EFL) objects across threads before then this will actually now cause your code to fail as it was invalid before to do this as no actual objects were threadsafe in EFL, so this will force things to "fail early". ecore_thread_main_loop_begin() and end() still work as this uses the eo domain adoption features to temporarily adopt a domain during this section and then return it when done. This returns speed back to eo brining the overhead in my tests of lookup for the elm genlist autobounce test in elementary from about 5-7% down to 2.5-2.6%. A steep drop. This does not mean everything is perfect. Still to do are: 1. Tests in the test suite 2. Some API's to help for sending objects from thread to thread 3. Make the eo call cache TLS data to make it also safe 4. Look at other locks in eo and probably move them to TLS data 5. Make eo resolve and call wrappers that call the real method func do recursive mutex wrapping of the given object IF it is a shared object to provide threadsafety transparently for shared objects (but adding some overhead as a result) 6. Test test est, and that is why this commit is going in now for wider testing 7. Decide how to make this work with sending IPC (between threads) 8. Deciding what makes an object sendable (a sendable property in base?) 9. Deciding what makes an object shareable (a sharable property in base?)
2016-09-07 01:53:33 -07:00
efl_domain_data_return(Efl_Id_Domain domain)
{
Eo_Id_Data *data = _eo_table_data_get();
if ((domain < EFL_ID_DOMAIN_MAIN) || (domain > EFL_ID_DOMAIN_THREAD))
{
ERR("Invalid domain %i being returned to owning thread", domain);
return EINA_FALSE;
}
if (domain == data->local_domain)
{
ERR("Cannot return the local domain %i back to its owner [data=%p]", domain, data);
eo - make eo id table TLS private data for thread safety and speed This moved all the eoid tables, eoid lookup caches, generation count information ad eo_isa cache into a TLS segment of memory that is thread private. There is also a shared domain for EO objects that all threads can access, but it has an added cost of a lock. This means objects accessed outside the thread they were created in cannot be accessed by another thread unless they are adopted in temporarily, or create4d with the shared domain active at the time of creation. child objects will use their parent object domain if created with a parent object passed in. If you were accessing EO (EFL) objects across threads before then this will actually now cause your code to fail as it was invalid before to do this as no actual objects were threadsafe in EFL, so this will force things to "fail early". ecore_thread_main_loop_begin() and end() still work as this uses the eo domain adoption features to temporarily adopt a domain during this section and then return it when done. This returns speed back to eo brining the overhead in my tests of lookup for the elm genlist autobounce test in elementary from about 5-7% down to 2.5-2.6%. A steep drop. This does not mean everything is perfect. Still to do are: 1. Tests in the test suite 2. Some API's to help for sending objects from thread to thread 3. Make the eo call cache TLS data to make it also safe 4. Look at other locks in eo and probably move them to TLS data 5. Make eo resolve and call wrappers that call the real method func do recursive mutex wrapping of the given object IF it is a shared object to provide threadsafety transparently for shared objects (but adding some overhead as a result) 6. Test test est, and that is why this commit is going in now for wider testing 7. Decide how to make this work with sending IPC (between threads) 8. Deciding what makes an object sendable (a sendable property in base?) 9. Deciding what makes an object shareable (a sharable property in base?)
2016-09-07 01:53:33 -07:00
return EINA_FALSE;
}
data->tables[domain] = NULL;
_efl_domain_pop(data);
return EINA_TRUE;
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API Eina_Bool
eo - make eo id table TLS private data for thread safety and speed This moved all the eoid tables, eoid lookup caches, generation count information ad eo_isa cache into a TLS segment of memory that is thread private. There is also a shared domain for EO objects that all threads can access, but it has an added cost of a lock. This means objects accessed outside the thread they were created in cannot be accessed by another thread unless they are adopted in temporarily, or create4d with the shared domain active at the time of creation. child objects will use their parent object domain if created with a parent object passed in. If you were accessing EO (EFL) objects across threads before then this will actually now cause your code to fail as it was invalid before to do this as no actual objects were threadsafe in EFL, so this will force things to "fail early". ecore_thread_main_loop_begin() and end() still work as this uses the eo domain adoption features to temporarily adopt a domain during this section and then return it when done. This returns speed back to eo brining the overhead in my tests of lookup for the elm genlist autobounce test in elementary from about 5-7% down to 2.5-2.6%. A steep drop. This does not mean everything is perfect. Still to do are: 1. Tests in the test suite 2. Some API's to help for sending objects from thread to thread 3. Make the eo call cache TLS data to make it also safe 4. Look at other locks in eo and probably move them to TLS data 5. Make eo resolve and call wrappers that call the real method func do recursive mutex wrapping of the given object IF it is a shared object to provide threadsafety transparently for shared objects (but adding some overhead as a result) 6. Test test est, and that is why this commit is going in now for wider testing 7. Decide how to make this work with sending IPC (between threads) 8. Deciding what makes an object sendable (a sendable property in base?) 9. Deciding what makes an object shareable (a sharable property in base?)
2016-09-07 01:53:33 -07:00
efl_compatible(const Eo *obj, const Eo *obj_target)
{
Efl_Id_Domain domain1 = ((Eo_Id)obj >> SHIFT_DOMAIN) & MASK_DOMAIN;
Efl_Id_Domain domain2 = ((Eo_Id)obj_target >> SHIFT_DOMAIN) & MASK_DOMAIN;
if (domain1 == domain2) return EINA_TRUE;
DBG("Object %p and %p are not compatible. Domain %i and %i do not match",
obj, obj_target, domain1, domain2);
return EINA_FALSE;
eo - make eo id table TLS private data for thread safety and speed This moved all the eoid tables, eoid lookup caches, generation count information ad eo_isa cache into a TLS segment of memory that is thread private. There is also a shared domain for EO objects that all threads can access, but it has an added cost of a lock. This means objects accessed outside the thread they were created in cannot be accessed by another thread unless they are adopted in temporarily, or create4d with the shared domain active at the time of creation. child objects will use their parent object domain if created with a parent object passed in. If you were accessing EO (EFL) objects across threads before then this will actually now cause your code to fail as it was invalid before to do this as no actual objects were threadsafe in EFL, so this will force things to "fail early". ecore_thread_main_loop_begin() and end() still work as this uses the eo domain adoption features to temporarily adopt a domain during this section and then return it when done. This returns speed back to eo brining the overhead in my tests of lookup for the elm genlist autobounce test in elementary from about 5-7% down to 2.5-2.6%. A steep drop. This does not mean everything is perfect. Still to do are: 1. Tests in the test suite 2. Some API's to help for sending objects from thread to thread 3. Make the eo call cache TLS data to make it also safe 4. Look at other locks in eo and probably move them to TLS data 5. Make eo resolve and call wrappers that call the real method func do recursive mutex wrapping of the given object IF it is a shared object to provide threadsafety transparently for shared objects (but adding some overhead as a result) 6. Test test est, and that is why this commit is going in now for wider testing 7. Decide how to make this work with sending IPC (between threads) 8. Deciding what makes an object sendable (a sendable property in base?) 9. Deciding what makes an object shareable (a sharable property in base?)
2016-09-07 01:53:33 -07:00
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API Eina_Bool
efl_class_override_register(const Efl_Class *klass, const Efl_Class *override)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(klass, EINA_FALSE);
EINA_SAFETY_ON_NULL_RETURN_VAL(override, EINA_FALSE);
EINA_SAFETY_ON_TRUE_RETURN_VAL(!efl_isa(override, klass), EINA_FALSE);
if (!class_overrides)
class_overrides = eina_hash_pointer_new(NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(class_overrides, EINA_FALSE);
eina_hash_set(class_overrides, &klass, override);
return EINA_TRUE;
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API Eina_Bool
efl_class_override_unregister(const Efl_Class *klass, const Efl_Class *override)
{
const Efl_Class *set;
EINA_SAFETY_ON_NULL_RETURN_VAL(klass, EINA_FALSE);
EINA_SAFETY_ON_NULL_RETURN_VAL(override, EINA_FALSE);
if (!class_overrides) return EINA_TRUE;
set = eina_hash_find(class_overrides, &klass);
if (set != override) return EINA_FALSE;
return eina_hash_del_by_key(class_overrides, &klass);
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API Eina_Bool
efl_destructed_is(const Eo *obj_id)
{
Eina_Bool is;
EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, EINA_FALSE);
is = obj->destructed;
EO_OBJ_DONE(obj_id);
return is;
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API void
efl_manual_free_set(Eo *obj_id, Eina_Bool manual_free)
{
EO_OBJ_POINTER_RETURN(obj_id, obj);
obj->manual_free = manual_free;
EO_OBJ_DONE(obj_id);
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API Eina_Bool
efl_manual_free(Eo *obj_id)
{
EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, EINA_FALSE);
// rare to use goto to keep instruction cache cleaner
if (obj->manual_free == EINA_FALSE) goto err_manual_free;
// rare to use goto to keep instruction cache cleaner
if (!obj->destructed) goto err_not_destructed;
_eo_free(obj, EINA_TRUE);
EO_OBJ_DONE(obj_id);
return EINA_TRUE;
err_manual_free:
ERR("Tried to manually free the object %p while the option has not been set; see efl_manual_free_set for more information.", obj);
goto err;
err_not_destructed:
ERR("Tried deleting the object %p while still referenced(%d).", obj_id, obj->refcount);
goto err;
err:
EO_OBJ_DONE(obj_id);
return EINA_FALSE;
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API const char *
efl_debug_name_get(const Eo *obj_id)
{
const char *override = "";
const char *name, *clsname;
Eina_Strbuf *sb;
if (!obj_id) return "(null)";
if (_eo_is_a_class(obj_id))
{
const char *clstype;
EO_CLASS_POINTER(obj_id, klass);
if (!klass || !klass->desc)
return eina_slstr_printf("Invalid_Class_ID(invalid)@%p", obj_id);
switch (klass->desc->type)
{
case EFL_CLASS_TYPE_REGULAR: clstype = "regular"; break;
case EFL_CLASS_TYPE_REGULAR_NO_INSTANT: clstype = "abstract"; break;
case EFL_CLASS_TYPE_INTERFACE: clstype = "interface"; break;
case EFL_CLASS_TYPE_MIXIN: clstype = "mixin"; break;
default: clstype = "invalid"; break;
}
return eina_slstr_printf("%s(%s)@%p", klass->desc->name, clstype, obj_id);
}
EO_OBJ_POINTER(obj_id, obj);
if (!obj) return eina_slstr_printf("Invalid_Object_ID@%p", obj_id);
sb = eina_strbuf_new();
name = efl_name_get(obj_id);
clsname = obj->klass->desc->name;
if (_obj_is_override(obj)) override = "(override)";
if (name)
eina_strbuf_append_printf(sb, "%s%s@%p[%d]:'%s'", clsname, override, obj_id, (int) obj->refcount, name);
else
eina_strbuf_append_printf(sb, "%s%s@%p[%d]", clsname, override, obj_id, (int) obj->refcount);
if (!obj->cur_klass)
{
efl_debug_name_override((Eo *) obj_id, sb);
}
else
{
if (obj->super)
efl_debug_name_override(efl_super(obj_id, (Efl_Class *) obj->cur_klass->header.id), sb);
else
efl_debug_name_override(efl_cast(obj_id, (Efl_Class *) obj->cur_klass->header.id), sb);
obj->super = EINA_FALSE;
obj->cur_klass = NULL;
}
EO_OBJ_DONE(obj_id);
return eina_slstr_strbuf_new(sb);
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API int
efl_callbacks_cmp(const Efl_Callback_Array_Item *a, const Efl_Callback_Array_Item *b)
{
if (a->desc == b->desc) return 0;
else if (a->desc > b->desc) return 1;
else return -1;
}
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
#ifdef EO_DEBUG
/* NOTE: cannot use ecore_time_get()! */
static inline double
_eo_log_time_now(void)
{
#ifdef _WIN32
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
return evil_time_get();
#elif defined(__APPLE__) && defined(__MACH__)
static double clk_conv = -1.0;
if (EINA_UNLIKELY(clk_conv < 0))
{
mach_timebase_info_data_t info;
kern_return_t err = mach_timebase_info(&info);
if (err == 0)
clk_conv = 1e-9 * (double)info.numer / (double)info.denom;
else
clk_conv = 1e-9;
}
return clk_conv * mach_absolute_time();
#else
#if defined (HAVE_CLOCK_GETTIME)
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
struct timespec t;
static int clk_id = -1;
if (EINA_UNLIKELY(clk_id == -2)) goto try_gettimeofday;
if (EINA_UNLIKELY(clk_id == -1))
{
retry_clk_id:
clk_id = CLOCK_MONOTONIC;
if (EINA_UNLIKELY(clock_gettime(clk_id, &t)))
{
WRN("CLOCK_MONOTONIC failed!");
clk_id = CLOCK_REALTIME;
if (EINA_UNLIKELY(clock_gettime(clk_id, &t)))
{
WRN("CLOCK_REALTIME failed!");
clk_id = -2;
goto try_gettimeofday;
}
}
}
else
{
if (EINA_UNLIKELY(clock_gettime(clk_id, &t)))
{
WRN("clk_id=%d previously ok, now failed... retry", clk_id);
goto retry_clk_id;
}
}
return (double)t.tv_sec + (((double)t.tv_nsec) / 1000000000.0);
try_gettimeofday:
#endif
{
struct timeval timev;
gettimeofday(&timev, NULL);
return (double)timev.tv_sec + (((double)timev.tv_usec) / 1000000);
}
#endif
}
#ifdef HAVE_BACKTRACE
typedef struct _Eo_Log_Obj_Entry {
Eo_Id id;
const _Eo_Object *obj;
const _Efl_Class *klass;
double timestamp;
Eo_Ref_Op ref_op;
unsigned bt_size;
unsigned bt_hits;
uintptr_t bt_hash;
void *bt[];
} Eo_Log_Obj_Entry;
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)
{
const Eo_Log_Obj_Entry *entry;
Eina_Array_Iterator it;
unsigned int idx;
*added_idx = -1;
*added = NULL;
*deleted = NULL;
eina_spinlock_take(&_eo_log_objs_lock);
EINA_ARRAY_ITER_NEXT(&_eo_log_objs, idx, entry, it)
{
if (EINA_UNLIKELY(id == entry->id))
{
if (entry->ref_op == EO_REF_OP_FREE)
*deleted = entry;
else if (entry->ref_op == EO_REF_OP_NEW)
{
*added_idx = idx;
*added = entry;
*deleted = NULL; /* forget previous add, if any */
}
}
}
eina_spinlock_release(&_eo_log_objs_lock);
}
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
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)
{
unsigned i;
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
eina_log_print(_eo_log_objs_dom, log_level, file, func_name, line,
"%s obj_id=%p obj=%p, class=%p (%s) [%0.4fs, %0.4fs ago] [%d hits]:",
_eo_ref_op_str[entry->ref_op],
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
(void *)entry->id,
entry->obj,
entry->klass,
entry->klass->desc->name,
entry->timestamp - _eo_log_time_start, now - entry->timestamp,
entry->bt_hits);
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
// Skip EO_API and _eo_log_obj_ref_op()
for (i = 2; i < entry->bt_size; i++)
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
{
#ifdef HAVE_DLADDR
Dl_info info;
if (dladdr(entry->bt[i], &info))
{
if (info.dli_sname)
{
eina_log_print(_eo_log_objs_dom, log_level, file, func_name, line,
" 0x%016llx: %s+%llu (in %s 0x%llx)",
(unsigned long long)(uintptr_t)entry->bt[i],
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
info.dli_sname,
(unsigned long long)(uintptr_t)((char *)entry->bt[i] - (char *)info.dli_saddr),
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
info.dli_fname ? info.dli_fname : "??",
(unsigned long long)(uintptr_t)info.dli_fbase);
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
continue;
}
else if (info.dli_fname)
{
const char *fname;
#ifdef _WIN32
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
fname = strrchr(info.dli_fname, '\\');
#else
fname = strrchr(info.dli_fname, '/');
#endif
if (!fname) fname = info.dli_fname;
else fname++;
eina_log_print(_eo_log_objs_dom, log_level, file, func_name, line,
" 0x%016llx: %s+%llu (in %s 0x%llx)",
(unsigned long long)(uintptr_t)entry->bt[i],
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
fname,
(unsigned long long)(uintptr_t)((char *)entry->bt[i] - (char *)info.dli_fbase),
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
info.dli_fname,
(unsigned long long)(uintptr_t)info.dli_fbase);
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
continue;
}
}
#endif
eina_log_print(_eo_log_objs_dom, log_level, func_name, file, line,
" 0x%016llx", (unsigned long long)(uintptr_t)entry->bt[i]);
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
}
}
#endif
#ifdef HAVE_BACKTRACE
static uintptr_t
_eo_log_obj_backtrace_hash(Eo_Log_Obj_Entry *entry)
{
if (!entry->bt_hash)
{
entry->bt_hash = (uintptr_t) 4294967291;
for (unsigned k = 0; k < entry->bt_size; k++)
entry->bt_hash ^= ((uintptr_t) (entry->bt[k]));
}
return entry->bt_hash;
}
static Eina_Bool
_eo_log_obj_entry_is_new_backtrace(const Eina_List *entries, Eo_Log_Obj_Entry *entry)
{
Eina_Bool ret = EINA_TRUE;
Eo_Log_Obj_Entry *other;
const Eina_List *li;
uintptr_t hash;
hash = _eo_log_obj_backtrace_hash(entry);
EINA_LIST_FOREACH(entries, li, other)
if (_eo_log_obj_backtrace_hash(other) == hash)
{
other->bt_hits++;
ret = EINA_FALSE;
}
return ret;
}
static Eina_List *
_eo_log_obj_find_all(const Eo_Id id, int start_idx)
{
Eo_Log_Obj_Entry *entry;
Eina_List *entries = NULL;
unsigned int idx;
eina_spinlock_take(&_eo_log_objs_lock);
for (idx = start_idx + 1; idx < eina_array_count(&_eo_log_objs); idx++)
{
entry = eina_array_data_get(&_eo_log_objs, idx);
if (entry->id != id) continue;
if (entry->ref_op > _eo_log_objs_level) continue;
if (entry->ref_op == EO_REF_OP_FREE) break;
if (_eo_log_obj_entry_is_new_backtrace(entries, entry))
entries = eina_list_append(entries, entry);
}
eina_spinlock_release(&_eo_log_objs_lock);
return entries;
}
#endif
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
inline void
_eo_log_obj_report(const Eo_Id id, int log_level, const char *func_name, const char *file, int line)
{
#ifdef HAVE_BACKTRACE
const Eo_Log_Obj_Entry *added, *deleted;
Eo_Log_Obj_Entry *current = NULL;
int added_idx = -1;
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
double now;
if (EINA_LIKELY(!_eo_log_objs_level)) return;
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
_eo_log_obj_find(id, &added, &added_idx, &deleted);
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
if ((!added) && (!deleted))
{
if ((!_eo_log_objs_debug.len) && (!_eo_log_objs_no_debug.len))
{
eina_log_print(_eo_log_objs_dom, log_level, file, func_name, line,
"obj_id=%p was neither created or deleted.", (void *)id);
}
else if ((_eo_log_objs_debug.len) && (_eo_log_objs_no_debug.len))
{
eina_log_print(_eo_log_objs_dom, log_level, file, func_name, line,
"obj_id=%p was neither created or deleted (EO_LIFECYCLE_DEBUG='%s', EO_LIFECYCLE_NO_DEBUG='%s').",
(void *)id, getenv("EO_LIFECYCLE_DEBUG"), getenv("EO_LIFECYCLE_NO_DEBUG"));
}
else if (_eo_log_objs_debug.len)
{
eina_log_print(_eo_log_objs_dom, log_level, file, func_name, line,
"obj_id=%p was neither created or deleted (EO_LIFECYCLE_DEBUG='%s').",
(void *)id, getenv("EO_LIFECYCLE_DEBUG"));
}
else
{
eina_log_print(_eo_log_objs_dom, log_level, file, func_name, line,
"obj_id=%p was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='%s').",
(void *)id, getenv("EO_LIFECYCLE_NO_DEBUG"));
}
return;
}
now = _eo_log_time_now();
#ifdef HAVE_BACKTRACE
if ((_eo_log_objs_backtrace >= 0) && deleted)
{
void **bt = NULL;
int size = 0;
if (_eo_log_objs_backtrace > 0)
{
bt = alloca(sizeof(void *) * (_eo_log_objs_backtrace + 2));
size = backtrace(bt, (_eo_log_objs_backtrace + 2));
if (EINA_UNLIKELY(size < 1))
{
bt = NULL;
size = 0;
}
}
current = calloc(1, sizeof(Eo_Log_Obj_Entry) + size * sizeof(void *));
if (EINA_UNLIKELY(!current)) return;
current->id = id;
current->timestamp = now;
current->obj = deleted->obj;
current->klass = deleted->klass;
current->ref_op = EO_REF_OP_NONE;
current->bt_size = size;
current->bt_hash = 0;
current->bt_hits = 1;
if (bt && size)
memcpy(current->bt, bt, size * sizeof(void *));
}
#endif
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
if (added)
{
_eo_log_obj_entry_show(added, log_level, func_name, file, line, now);
if (_eo_log_objs_level > EO_REF_OP_FREE)
{
Eina_List *entries = _eo_log_obj_find_all(id, added_idx);
const Eo_Log_Obj_Entry *entry;
EINA_LIST_FREE(entries, entry)
_eo_log_obj_entry_show(entry, log_level, func_name, file, line, now);
}
}
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
if (deleted)
{
_eo_log_obj_entry_show(deleted, log_level, func_name, file, line, now);
eina_log_print(_eo_log_objs_dom, log_level, file, func_name, line,
"obj_id=%p was already deleted %0.4f seconds ago!",
(void *)id, now - deleted->timestamp);
}
if (current)
{
eina_log_print(_eo_log_objs_dom, log_level, file, func_name, line,
"obj_id=%p current use from:", (void *)id);
_eo_log_obj_entry_show(current, log_level, func_name, file, line, now);
free(current);
}
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
#else
(void)id;
(void)log_level;
(void)func_name;
(void)file;
(void)line;
#endif
}
#ifdef HAVE_BACKTRACE
static Eo_Log_Obj_Entry *
_eo_log_obj_entry_ref_op(const _Eo_Object *obj, Eo_Ref_Op refop, unsigned size, void *const *bt)
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
{
Eo_Log_Obj_Entry *entry;
Eina_Bool ret;
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
entry = calloc(1, sizeof(Eo_Log_Obj_Entry) + size * sizeof(void *));
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
if (EINA_UNLIKELY(!entry)) return NULL;
entry->id = (Eo_Id)_eo_obj_id_get(obj);
entry->timestamp = _eo_log_time_now();
entry->obj = obj;
entry->klass = obj->klass;
entry->ref_op = refop;
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
entry->bt_size = size;
entry->bt_hash = 0;
entry->bt_hits = 1;
if (size && bt)
memcpy(entry->bt, bt, size * sizeof(void *));
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
eina_spinlock_take(&_eo_log_objs_lock);
ret = eina_array_push(&_eo_log_objs, entry);
eina_spinlock_release(&_eo_log_objs_lock);
if (!ret)
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
{
free(entry);
return NULL;
}
return entry;
}
static inline void
_eo_log_obj_entry_free(Eo_Log_Obj_Entry *entry)
{
free(entry);
}
#endif
static int
_eo_class_name_slice_cmp(const void *pa, const void *pb)
{
const Eina_Slice *a = pa;
const Eina_Slice *b = pb;
if (a->len < b->len) return -1;
if (a->len > b->len) return 1;
return memcmp(a->mem, b->mem, a->len);
}
static Eina_Bool
_eo_log_obj_desired(const _Eo_Object *obj)
{
Eina_Slice cls_name;
if (EINA_LIKELY((_eo_log_objs_debug.len == 0) &&
(_eo_log_objs_no_debug.len == 0)))
return EINA_TRUE;
cls_name.mem = obj->klass->desc->name;
cls_name.len = strlen(cls_name.mem);
if (_eo_log_objs_no_debug.len)
{
if (eina_inarray_search_sorted(&_eo_log_objs_no_debug, &cls_name, _eo_class_name_slice_cmp) >= 0)
return EINA_FALSE;
}
if (!_eo_log_objs_debug.len)
return EINA_TRUE;
if (eina_inarray_search_sorted(&_eo_log_objs_debug, &cls_name, _eo_class_name_slice_cmp) >= 0)
return EINA_TRUE;
return EINA_FALSE;
}
static void
_eo_log_obj_ref_op(const _Eo_Object *obj, Eo_Ref_Op ref_op)
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
{
if (EINA_LIKELY(_eo_log_objs_level < ref_op)) return;
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
if (EINA_LIKELY(!_eo_log_obj_desired(obj))) return;
#ifdef HAVE_BACKTRACE
if (_eo_log_objs_backtrace >= 0)
{
void **bt = NULL;
int size = 0;
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
if (_eo_log_objs_backtrace > 0)
{
bt = alloca(sizeof(void *) * (_eo_log_objs_backtrace + 2));
size = backtrace(bt, (_eo_log_objs_backtrace + 2));
if (EINA_UNLIKELY(size < 1)) return;
}
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
_eo_log_obj_entry_ref_op(obj, ref_op, size, bt);
}
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
#endif
EINA_LOG_DOM_DBG(_eo_log_objs_dom,
"%s obj_id=%p class=%p (%s) [%0.4f]",
_eo_ref_op_str[ref_op], _eo_obj_id_get(obj),
obj->klass, obj->klass->desc->name,
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
_eo_log_time_now() - _eo_log_time_start);
}
static inline void
_eo_log_obj_init(void)
{
const char *s;
_eo_log_objs_dom = eina_log_domain_register("eo_lifecycle", EINA_COLOR_BLUE);
_eo_log_time_start = _eo_log_time_now();
#ifdef HAVE_BACKTRACE
eina_array_step_set(&_eo_log_objs, sizeof(Eina_Array), 4096);
eina_spinlock_new(&_eo_log_objs_lock);
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
#endif
eina_inarray_step_set(&_eo_log_objs_debug, sizeof(Eina_Inarray), sizeof(Eina_Slice), 0);
eina_inarray_step_set(&_eo_log_objs_no_debug, sizeof(Eina_Inarray), sizeof(Eina_Slice), 0);
s = getenv("EO_LIFECYCLE_BACKTRACE");
if (s && *s)
{
_eo_log_objs_backtrace = atoi(s);
if (_eo_log_objs_backtrace > EO_LOG_OBJS_BACKTRACE_MAX)
_eo_log_objs_backtrace = EO_LOG_OBJS_BACKTRACE_MAX;
else if (_eo_log_objs_backtrace < 0)
_eo_log_objs_backtrace = 0;
}
else
_eo_log_objs_backtrace = EO_LOG_OBJS_BACKTRACE_DEFAULT;
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
s = getenv("EO_LIFECYCLE_DEBUG");
if ((s) && (s[0] != '\0'))
{
char *es;
int lvl = (int)strtol(s, &es, 10);
_eo_log_objs_level = EO_REF_OP_FREE;
if ((es != s) && (*es == ':'))
{
if (lvl >= 3)
{
_eo_log_objs_level = EO_REF_OP_REUSE;
EINA_LOG_DOM_DBG(_eo_log_objs_dom,
"will log new, free, ref, unref and reuse");
}
else if (lvl == 2)
{
_eo_log_objs_level = EO_REF_OP_UNREF;
EINA_LOG_DOM_DBG(_eo_log_objs_dom,
"will log new, free, ref and unref");
}
s = es + 1;
}
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
if ((strcmp(s, "*") == 0) || (strcmp(s, "1") == 0))
{
EINA_LOG_DOM_DBG(_eo_log_objs_dom,
"will log all object allocation and free");
}
else
{
Eina_Slice slice;
const Eina_Slice *itr;
do
{
char *p = strchr(s, ',');
slice.mem = s;
if (p)
{
slice.len = p - s;
s = p + 1;
}
else
{
slice.len = strlen(s);
s = NULL;
}
eina_inarray_push(&_eo_log_objs_debug, &slice);
}
while (s);
eina_inarray_sort(&_eo_log_objs_debug, _eo_class_name_slice_cmp);
EINA_INARRAY_FOREACH(&_eo_log_objs_debug, itr)
{
EINA_LOG_DOM_DBG(_eo_log_objs_dom,
"will log class '" EINA_SLICE_STR_FMT "'",
EINA_SLICE_STR_PRINT(*itr));
}
}
#ifndef HAVE_BACKTRACE
WRN("EO_LIFECYCLE_DEBUG='%s' but your system has no backtrace()!", s);
#endif
}
if (EINA_LIKELY(!_eo_log_objs_level)) return;
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
DBG("logging object allocation and free, use EINA_LOG_LEVELS=eo_lifecycle:4");
s = getenv("EO_LIFECYCLE_NO_DEBUG");
if ((s) && (s[0] != '\0'))
{
if ((strcmp(s, "*") == 0) || (strcmp(s, "1") == 0))
{
EINA_LOG_DOM_ERR(_eo_log_objs_dom,
"expected class names to not log allocation and free, got '%s'", s);
}
else
{
Eina_Slice slice;
const Eina_Slice *itr;
do
{
char *p = strchr(s, ',');
slice.mem = s;
if (p)
{
slice.len = p - s;
s = p + 1;
}
else
{
slice.len = strlen(s);
s = NULL;
}
eina_inarray_push(&_eo_log_objs_no_debug, &slice);
}
while (s);
eina_inarray_sort(&_eo_log_objs_no_debug, _eo_class_name_slice_cmp);
EINA_INARRAY_FOREACH(&_eo_log_objs_no_debug, itr)
{
EINA_LOG_DOM_DBG(_eo_log_objs_dom,
"will NOT log class '" EINA_SLICE_STR_FMT "'",
EINA_SLICE_STR_PRINT(*itr));
}
}
}
}
static inline void
_eo_log_obj_shutdown(void)
{
#ifdef HAVE_BACKTRACE
Eo_Log_Obj_Entry *entry;
Eina_Array_Iterator it;
unsigned int idx;
eina_spinlock_take(&_eo_log_objs_lock);
if (eina_log_domain_level_check(_eo_log_objs_dom, EINA_LOG_LEVEL_INFO))
{
void * const *itr = _eo_log_objs.data;
void * const *itr_end = itr + _eo_log_objs.count;
double now = _eo_log_time_now();
size_t leaks = 0;
for (; itr < itr_end; itr++)
{
void * const *cur;
2017-02-14 23:23:44 -08:00
entry = *itr;
if (entry->ref_op == EO_REF_OP_FREE) continue;
for (cur = itr + 1; cur < itr_end; cur++)
{
const Eo_Log_Obj_Entry *cur_entry = *cur;
if (EINA_UNLIKELY((cur_entry->id == entry->id) && (cur_entry->ref_op == EO_REF_OP_FREE)))
break;
}
if (EINA_UNLIKELY(cur == itr_end))
{
EINA_LOG_DOM_INFO(_eo_log_objs_dom,
"leaking obj_id=%p obj=%p class=%p (%s) [%0.4fs, %0.4f ago]",
(void *)entry->id,
entry->obj,
entry->klass,
entry->klass->desc->name,
entry->timestamp - _eo_log_time_start, now - entry->timestamp);
_eo_log_obj_entry_show(entry, EINA_LOG_LEVEL_DBG, __func__, __FILE__, __LINE__, now);
leaks++;
}
}
if (leaks)
EINA_LOG_DOM_WARN(_eo_log_objs_dom, "Leaked %zd objects! Check details with EINA_LOG_LEVELS=eo_lifecycle:4", leaks);
else
EINA_LOG_DOM_INFO(_eo_log_objs_dom, "No leaked objects!");
}
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
EINA_ARRAY_ITER_NEXT(&_eo_log_objs, idx, entry, it)
_eo_log_obj_entry_free(entry);
eina_array_flush(&_eo_log_objs);
eina_spinlock_release(&_eo_log_objs_lock);
eina_spinlock_free(&_eo_log_objs_lock);
eo: allow valgrind-like tracking of object lifecycle. Eo pointer indirection is super nice as it avoids you to access invalid memory, but this extra checks inhibits valgrind's own tracking of memory lifecycle, usually it would report when the object was created and when the object is deleted, both as stack traces. This commits introduces logging of object creation and destruction under its own eina_log_domain and controlled by EO_LIFECYCLE_DEBUG and EO_LIFECYCLE_NO_DEBUG envvars. These will only be available if compiled with EO_DEBUG, thus shouldn't cause any performance hits on production code. Running a bogus app with invalid efl_class_name_get() and double efl_del() will report as below: ```sh $ export EO_LIFECYCLE_NO_DEBUG=Efl_Loop_Timer,Efl_Promise,Efl_Future $ export EO_LIFECYCLE_DEBUG=1 $ export EINA_LOG_LEVELS=eo_lifecycle:4 $ /tmp/bogus_app DBG:eo_lifecycle lib/eo/eo.c:2712 _eo_log_obj_init() will log all object allocation and free DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Future' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Promise' DBG:eo_lifecycle lib/eo/eo.c:2788 _eo_log_obj_init() will NOT log class 'Efl_Loop_Timer' DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35a1aa0 obj_id=0x4000000002cf38ef class=0x563fa35a1450 (Efl_Vpath_Core) [0.0004] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35af8d0 obj_id=0x4000000006cf38f0 class=0x563fa35aecf0 (Efl_Loop) [0.0005] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0055] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0056] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0057] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0058] DBG:eo_lifecycle lib/eo/eo.c:2665 _eo_log_obj_new() new obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0058] will efl_class_name_get() with invalid handle: ERR:eo lib/eo/eo.c:1013 efl_class_name_get() Class (0x2000000000000029) is an invalid ref. ERR:eo_lifecycle lib/eo/eo.c:1013 efl_class_name_get() obj_id=0x2000000000000029 was neither created or deleted (EO_LIFECYCLE_NO_DEBUG='Efl_Loop_Timer,Efl_Promise,Efl_Future'). DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35df980 obj_id=0x40000000a6cf3918 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35dfc30 obj_id=0x40000000aacf3919 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d75b0 obj_id=0x4000000086cf3910 class=0x563fa35d66b0 (Efl_Io_Queue) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d8f70 obj_id=0x400000008acf3911 class=0x563fa35d7860 (Efl_Io_Copier) [0.0061] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d6470 obj_id=0x4000000082cf390f class=0x563fa35d0d60 (Efl_Net_Dialer_Tcp) [0.0063] DBG:eo_lifecycle lib/eo/eo.c:2688 _eo_log_obj_free() free obj=0x563fa35d61a0 obj_id=0x400000007ecf390e class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063] will double free: ERR:eo ../src/lib/eo/efl_object.eo.c:78 efl_del() EOID 0x400000007ecf390e is not a valid object. EOID domain=0, current_domain=0, local_domain=0. EOID generation=2cf390e, id=1f, ref=1, super=0. Thread self=main. Available domains [0 1 ]. Maybe it has been deleted or does not belong to your thread? ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e created obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0054s, 0.0009 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d0ea: libeo_dbg.so+0x90ea (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6ca62: _efl_add_internal_start+0x1c2 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc95f: bogus_app+0x295f (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e deleted obj=0x563fa35d61a0, class=0x563fa35d48f0 (Efl_Net_Dialer_Simple) [0.0063s, 0.0000 ago]: ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d8ba: libeo_dbg.so+0x98ba (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6d711: libeo_dbg.so+0x9711 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6beb8: libeo_dbg.so+0x7eb8 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc6c06e: _efl_object_call_end+0x4e (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0bc75725: efl_del+0x105 (in src/lib/eo/.libs/libeo_dbg.so 0x7f2c0bc64000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dcd54: lt-efl_net_dialer_simple_example+0x2d54 (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x007f2c0ace7291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x7f2c0acc7000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00563fa15dc48a: _start+0x2a (in /tmp/bogus_app 0x563fa15da000) ERR:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() obj_id=0x400000007ecf390e was already deleted 0.0000 seconds ago! ```
2016-12-02 14:48:37 -08:00
#endif
eina_inarray_flush(&_eo_log_objs_debug);
eina_inarray_flush(&_eo_log_objs_no_debug);
}
#endif
typedef struct
{
Eina_Iterator iterator;
unsigned int cur_kl_id;
} _Eo_Classes_Iterator;
static Eina_Bool
_eo_classes_iterator_next(Eina_Iterator *it, void **data)
{
_Eo_Classes_Iterator *eo_it = (_Eo_Classes_Iterator *)it;
if (eo_it->cur_kl_id == _eo_classes_last_id) return EINA_FALSE;
*data = _eo_class_id_get(_eo_classes[eo_it->cur_kl_id]);
eo_it->cur_kl_id++;
return EINA_TRUE;
}
static void
_eo_classes_iterator_free(Eina_Iterator *it)
{
EINA_MAGIC_SET(it, EINA_MAGIC_NONE);
free(it);
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API Eina_Iterator *
eo_classes_iterator_new(void)
{
_Eo_Classes_Iterator *it;
it = calloc(1, sizeof (*it));
if (!it) return NULL;
it->iterator.version = EINA_ITERATOR_VERSION;
it->iterator.next = _eo_classes_iterator_next;
it->iterator.free = _eo_classes_iterator_free;
EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
return (Eina_Iterator *)it;
}
typedef struct
{
Eina_Iterator iterator;
Eo_Id_Table_Data *tdata;
Table_Index mid_table_id;
Table_Index table_id;
Table_Index entry_id;
} _Eo_Objects_Iterator;
static Eina_Bool
_eo_objects_iterator_next(Eina_Iterator *it, void **data)
{
Table_Index mid_table_id, table_id, entry_id;
Eo_Id_Table_Data *tdata;
_Eo_Objects_Iterator *eo_it = (_Eo_Objects_Iterator *)it;
if (!eo_it->tdata) return EINA_FALSE;
tdata = eo_it->tdata;
mid_table_id = eo_it->mid_table_id;
table_id = eo_it->table_id;
entry_id = eo_it->entry_id;
while (mid_table_id < MAX_MID_TABLE_ID)
{
if (tdata->eo_ids_tables[mid_table_id])
{
while (table_id < MAX_TABLE_ID)
{
if (TABLE_FROM_IDS)
{
while (entry_id < MAX_ENTRY_ID)
{
_Eo_Id_Entry *entry = &(TABLE_FROM_IDS->entries[entry_id]);
if (entry->active)
{
Eo *obj = _eo_header_id_get((Eo_Header *) entry->ptr);
*data = obj;
eo_it->mid_table_id = mid_table_id;
eo_it->table_id = table_id;
eo_it->entry_id = entry_id + 1;
return EINA_TRUE;
}
entry_id++;
}
entry_id = 0;
}
table_id++;
}
table_id = 0;
}
mid_table_id++;
}
return EINA_FALSE;
}
static void
_eo_objects_iterator_free(Eina_Iterator *it)
{
EINA_MAGIC_SET(it, EINA_MAGIC_NONE);
free(it);
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API Eina_Iterator *
eo_objects_iterator_new(void)
{
_Eo_Objects_Iterator *it;
Eo_Id_Table_Data *tdata = _eo_table_data_table_get(_eo_table_data_get(), EFL_ID_DOMAIN_MAIN);
if (!tdata) return NULL;
it = calloc(1, sizeof (*it));
if (!it) return NULL;
it->tdata = tdata;
it->iterator.version = EINA_ITERATOR_VERSION;
it->iterator.next = _eo_objects_iterator_next;
it->iterator.free = _eo_objects_iterator_free;
EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
return (Eina_Iterator *)it;
}
static Eina_Bool
_eo_value_setup(const Eina_Value_Type *type EINA_UNUSED, void *mem)
{
Eo **tmem = mem;
*tmem = NULL;
return EINA_TRUE;
}
static Eina_Bool
_eo_value_flush(const Eina_Value_Type *type EINA_UNUSED, void *mem)
{
Eo **tmem = mem;
if (*tmem)
{
efl_unref(*tmem);
*tmem = NULL;
}
return EINA_TRUE;
}
static Eina_Bool
_eo_value_vset(const Eina_Value_Type *type EINA_UNUSED, void *mem, va_list args)
{
Eo **dst = mem;
Eo *src = va_arg(args, Eo *);
efl_replace(dst, src);
return EINA_TRUE;
}
static Eina_Bool
_eo_value_pset(const Eina_Value_Type *type EINA_UNUSED,
void *mem, const void *ptr)
{
Eo **dst = mem;
Eo * const *src = ptr;
2017-10-30 16:02:58 -07:00
efl_replace(dst, *src);
return EINA_TRUE;
}
static Eina_Bool
_eo_value_pget(const Eina_Value_Type *type EINA_UNUSED,
const void *mem, void *ptr)
{
Eo * const *src = mem;
Eo **dst = ptr;
*dst = *src;
return EINA_TRUE;
}
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)
{
Eo * const *eo = type_mem;
if (convert == EINA_VALUE_TYPE_STRINGSHARE ||
convert == EINA_VALUE_TYPE_STRING)
{
const char *other_mem;
char buf[256];
snprintf(buf, sizeof(buf), "Object id: %p, class: %s, name: %s",
*eo, efl_class_name_get(efl_class_get(*eo)),
efl_debug_name_get(*eo));
other_mem = buf;
return eina_value_type_pset(convert, convert_mem, &other_mem);
}
return EINA_FALSE;
}
static Eina_Bool
_eo_value_copy(const Eina_Value_Type *type EINA_UNUSED, const void *mem, void *ptr)
{
Eo * const *src = mem;
Eo **dst = ptr;
if (!src || !dst) return EINA_FALSE;
*dst = efl_ref(*src);
return EINA_TRUE;
}
static const Eina_Value_Type _EINA_VALUE_TYPE_OBJECT = {
.version = EINA_VALUE_TYPE_VERSION,
.value_size = sizeof(Eo *),
.name = "Efl_Object",
.setup = _eo_value_setup,
.flush = _eo_value_flush,
.copy = _eo_value_copy,
.compare = NULL,
.convert_to = _eo_value_convert_to,
.convert_from = NULL,
.vset = _eo_value_vset,
.pset = _eo_value_pset,
.pget = _eo_value_pget
};
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API const Eina_Value_Type *EINA_VALUE_TYPE_OBJECT = &_EINA_VALUE_TYPE_OBJECT;
static const Efl_Object_Property_Reflection*
_efl_class_reflection_find(const _Efl_Class *klass, const char *property_name)
{
const _Efl_Class **klass_iter = klass->extensions;
const Efl_Object_Property_Reflection_Ops *ref_ops = klass->reflection;
unsigned int i;
for (i = 0; ref_ops && i < ref_ops->count; ++i)
{
if (eina_streq(property_name, ref_ops->table[i].property_name))
return &ref_ops->table[i];
}
if (klass->parent)
{
const Efl_Object_Property_Reflection *ref;
ref = _efl_class_reflection_find(klass->parent, property_name);
if (ref) return ref;
}
for (; *klass_iter; klass_iter++)
{
const Efl_Object_Property_Reflection *ref;
ref = _efl_class_reflection_find(*klass_iter, property_name);
if (ref) return ref;
}
return NULL;
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API Eina_Error
efl_property_reflection_set(Eo *obj_id, const char *property_name, Eina_Value value)
{
Eina_Error r = EINA_ERROR_NOT_IMPLEMENTED;
Eina_Bool freed = EINA_FALSE;
EO_OBJ_POINTER_GOTO(obj_id, obj, end);
const Efl_Object_Property_Reflection *reflection = _efl_class_reflection_find(obj->klass, property_name);
if (reflection && reflection->set)
{
r = reflection->set(obj_id, value);
freed = EINA_TRUE;
}
end:
if (!freed) eina_value_flush(&value);
EO_OBJ_DONE(obj_id);
return r;
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API Eina_Value
efl_property_reflection_get(const Eo *obj_id, const char *property_name)
{
Eina_Value r = eina_value_error_init(EINA_ERROR_NOT_IMPLEMENTED);
EO_OBJ_POINTER_GOTO(obj_id, obj, end);
const Efl_Object_Property_Reflection *reflection = _efl_class_reflection_find(obj->klass, property_name);
if (reflection && reflection->get)
r = reflection->get(obj_id);
end:
EO_OBJ_DONE(obj_id);
return r;
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API Eina_Bool
efl_property_reflection_exist(Eo *obj_id, const char *property_name)
{
Eina_Bool r = EINA_FALSE;
EO_OBJ_POINTER_GOTO(obj_id, obj, end);
const Efl_Object_Property_Reflection *reflection = _efl_class_reflection_find(obj->klass, property_name);
if (reflection) r = EINA_TRUE;
end:
EO_OBJ_DONE(obj_id);
return r;
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API Efl_Class_Type
efl_class_type_get(const Efl_Class *klass_id)
{
EO_CLASS_POINTER_RETURN_VAL(klass_id, klass, EFL_CLASS_TYPE_INVALID);
return klass->desc->type;
}
eo: Rename EAPI macro to EO_API in Eo library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Reviewers: jptiz, lucas, vtorri, woohyun Reviewed By: jptiz, lucas, vtorri Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12203
2020-12-09 08:50:29 -08:00
EO_API Eina_Bool
efl_ownable_get(const Eo *obj)
{
int ref = efl_ref_count(obj);
if (efl_parent_get(obj))
ref --;
if (ref <= 0)
ERR("There is no free reference to pass this object. Please check that this object is really owned by you.");
return (ref > 0);
}