2012-05-01 00:40:14 -07:00
# ifndef _EO_PRIVATE_H
# define _EO_PRIVATE_H
2014-09-25 07:51:17 -07:00
# include <Eo.h>
2013-09-27 04:10:43 -07:00
# include <Eina.h>
2012-06-05 05:05:06 -07:00
# define EO_EINA_MAGIC 0xa186bc32
2012-05-14 00:35:19 -07:00
# define EO_EINA_MAGIC_STR "Eo"
2012-06-05 05:05:06 -07:00
# define EO_FREED_EINA_MAGIC 0xa186bb32
# define EO_FREED_EINA_MAGIC_STR "Eo - Freed object"
# define EO_CLASS_EINA_MAGIC 0xa186ba32
2016-08-09 06:10:05 -07:00
# define EO_CLASS_EINA_MAGIC_STR "Efl Class"
2012-05-14 00:35:19 -07:00
# define EO_MAGIC_RETURN_VAL(d, magic, ret) \
do { \
if ( ! EINA_MAGIC_CHECK ( d , magic ) ) \
{ \
EINA_MAGIC_FAIL ( d , magic ) ; \
return ret ; \
} \
} while ( 0 )
# define EO_MAGIC_RETURN(d, magic) \
do { \
if ( ! EINA_MAGIC_CHECK ( d , magic ) ) \
{ \
EINA_MAGIC_FAIL ( d , magic ) ; \
return ; \
} \
} while ( 0 )
2012-05-01 00:40:14 -07:00
extern int _eo_log_dom ;
2013-12-25 19:22:05 -08:00
# ifdef CRI
# undef CRI
2012-05-01 00:40:14 -07:00
# endif
2013-12-25 19:22:05 -08:00
# define CRI(...) EINA_LOG_DOM_CRIT(_eo_log_dom, __VA_ARGS__)
2012-05-01 00:40:14 -07:00
# ifdef ERR
# undef ERR
# endif
# define ERR(...) EINA_LOG_DOM_ERR(_eo_log_dom, __VA_ARGS__)
# ifdef WRN
# undef WRN
# endif
# define WRN(...) EINA_LOG_DOM_WARN(_eo_log_dom, __VA_ARGS__)
# ifdef INF
# undef INF
# endif
# define INF(...) EINA_LOG_DOM_INFO(_eo_log_dom, __VA_ARGS__)
# ifdef DBG
# undef DBG
# endif
# define DBG(...) EINA_LOG_DOM_DBG(_eo_log_dom, __VA_ARGS__)
2013-09-18 13:05:26 -07:00
typedef uintptr_t Eo_Id ;
2016-08-10 07:23:04 -07:00
typedef struct _Efl_Class _Efl_Class ;
2015-05-28 08:49:13 -07:00
typedef struct _Eo_Header Eo_Header ;
2017-04-17 22:16:31 -07:00
typedef struct _Efl_Object_Optional Efl_Object_Optional ;
2013-06-27 01:58:49 -07:00
/* Allocates an entry for the given object */
2016-09-07 01:53:33 -07:00
static inline Eo_Id _eo_id_allocate ( const _Eo_Object * obj , const Eo * parent_id ) ;
2013-06-27 01:58:49 -07:00
/* Releases an entry by the object id */
2013-07-01 01:09:02 -07:00
static inline void _eo_id_release ( const Eo_Id obj_id ) ;
2013-06-27 01:58:49 -07:00
2012-06-10 07:04:53 -07:00
void _eo_condtor_done ( Eo * obj ) ;
2016-05-18 10:12:39 -07:00
typedef struct _Dich_Chain1 Dich_Chain1 ;
typedef struct _Eo_Vtable
{
Dich_Chain1 * chain ;
unsigned int size ;
} Eo_Vtable ;
2016-05-19 03:33:17 -07:00
/* Clean the vtable. */
void _vtable_func_clean_all ( Eo_Vtable * vtable ) ;
2015-05-28 08:49:13 -07:00
struct _Eo_Header
2013-09-27 02:59:41 -07:00
{
Eo_Id id ;
} ;
2013-09-27 02:50:06 -07:00
2017-04-17 22:16:31 -07:00
struct _Efl_Object_Optional
{
Eo_Vtable * vtable ;
Eina_List * composite_objects ;
Efl_Del_Intercept del_intercept ;
} ;
2013-09-27 02:59:41 -07:00
struct _Eo_Object
{
2015-05-28 08:49:13 -07:00
Eo_Header header ;
2016-05-17 02:25:31 -07:00
EINA_INLIST ;
2016-08-09 06:10:05 -07:00
const _Efl_Class * klass ;
2013-06-27 01:58:49 -07:00
# ifdef EO_DEBUG
Eina_Inlist * xrefs ;
Eina_Inlist * data_xrefs ;
# endif
2017-04-17 22:16:31 -07:00
const Efl_Object_Optional * opt ; // eina cow
2017-04-18 03:57:53 -07:00
_Efl_Class * cur_klass ;
2013-06-27 01:58:49 -07:00
2016-05-17 01:39:12 -07:00
short refcount ;
2016-07-12 02:26:23 -07:00
short user_refcount ;
2016-05-18 07:02:09 -07:00
# ifdef EO_DEBUG
2016-05-17 01:39:12 -07:00
short datarefcount ;
2016-05-18 07:02:09 -07:00
# endif
2013-06-27 01:58:49 -07:00
Eina_Bool condtor_done : 1 ;
2014-08-29 01:55:02 -07:00
Eina_Bool finalized : 1 ;
2017-04-18 03:57:53 -07:00
Eina_Bool super : 1 ;
2018-04-04 15:37:11 -07:00
Eina_Bool invalidate : 1 ;
2018-05-01 13:32:12 -07:00
Eina_Bool is_invalidating : 1 ;
2018-05-03 11:36:28 -07:00
Eina_Bool parent : 1 ;
2018-05-14 14:47:39 -07:00
Eina_Bool unref_compensate : 1 ;
2018-05-03 16:32:11 -07:00
Eina_Bool allow_parent_unref : 1 ;
2013-06-27 01:58:49 -07:00
2019-01-23 16:29:47 -08:00
Eina_Bool noref_event : 1 ;
2014-11-18 07:24:39 -08:00
Eina_Bool del_triggered : 1 ;
Eina_Bool destructed : 1 ;
2013-06-27 01:58:49 -07:00
Eina_Bool manual_free : 1 ;
2017-12-04 21:31:22 -08:00
unsigned char auto_unref : 1 ; // unref after 1 call - hack for parts
2013-06-27 01:58:49 -07:00
} ;
2016-08-15 09:11:13 -07:00
/* How we search and store the implementations in classes. */
# define DICH_CHAIN_LAST_BITS 5
# define DICH_CHAIN_LAST_SIZE (1 << DICH_CHAIN_LAST_BITS)
# define DICH_CHAIN1(x) ((x) >> DICH_CHAIN_LAST_BITS)
# define DICH_CHAIN_LAST(x) ((x) & ((1 << DICH_CHAIN_LAST_BITS) - 1))
2017-04-17 22:16:31 -07:00
extern Eina_Cow * efl_object_optional_cow ;
# define EO_OPTIONAL_COW_WRITE(_obj) ({ Efl_Object_Optional *_cow = eina_cow_write(efl_object_optional_cow, (const Eina_Cow_Data**)&(_obj->opt)); _cow; })
# define EO_OPTIONAL_COW_END(_cow, _obj) eina_cow_done(efl_object_optional_cow, (const Eina_Cow_Data**)&(_obj->opt), _cow, EINA_TRUE)
# define EO_OPTIONAL_COW_SET(_obj, _field, _value) do { \
typeof ( _value ) _val = _value ; \
if ( _obj - > opt - > _field ! = _val ) { \
Efl_Object_Optional * _obj # # _cow = EO_OPTIONAL_COW_WRITE ( _obj ) ; \
_obj # # _cow - > _field = _val ; \
EO_OPTIONAL_COW_END ( _obj # # _cow , _obj ) ; \
} } while ( 0 )
# define EO_VTABLE(_obj) ((_obj)->opt->vtable ?: &((_obj)->klass->vtable))
2016-08-16 08:28:33 -07:00
typedef void ( * Eo_Op_Func_Type ) ( Eo * , void * class_data ) ;
2014-04-02 01:26:45 -07:00
2013-06-27 01:58:49 -07:00
typedef struct
{
2016-08-16 08:28:33 -07:00
Eo_Op_Func_Type func ;
2016-08-09 06:10:05 -07:00
const _Efl_Class * src ;
2013-06-27 01:58:49 -07:00
} op_type_funcs ;
2016-08-15 09:11:13 -07:00
typedef struct _Dich_Chain2
{
op_type_funcs funcs [ DICH_CHAIN_LAST_SIZE ] ;
unsigned short refcount ;
} Dich_Chain2 ;
2013-06-27 01:58:49 -07:00
struct _Dich_Chain1
{
2016-08-15 09:11:13 -07:00
Dich_Chain2 * chain2 ;
2013-06-27 01:58:49 -07:00
} ;
typedef struct
{
2016-08-09 06:10:05 -07:00
const _Efl_Class * klass ;
2013-06-27 01:58:49 -07:00
size_t offset ;
} Eo_Extension_Data_Offset ;
2016-08-09 06:10:05 -07:00
struct _Efl_Class
2013-06-27 01:58:49 -07:00
{
2015-05-28 08:49:13 -07:00
Eo_Header header ;
2013-09-27 02:50:06 -07:00
2016-08-09 06:10:05 -07:00
const _Efl_Class * parent ;
const Efl_Class_Description * desc ;
2016-05-18 10:12:39 -07:00
Eo_Vtable vtable ;
2013-06-27 01:58:49 -07:00
2016-08-09 06:10:05 -07:00
const _Efl_Class * * extensions ;
2013-06-27 01:58:49 -07:00
Eo_Extension_Data_Offset * extn_data_off ;
2016-08-09 06:10:05 -07:00
const _Efl_Class * * mro ;
2013-06-27 01:58:49 -07:00
2019-02-05 06:40:41 -08:00
const Efl_Object_Property_Reflection_Ops * reflection ;
2013-09-10 19:23:50 -07:00
/* cached object for faster allocation */
2013-09-11 00:08:06 -07:00
struct {
Eina_Trash * trash ;
2013-10-10 01:26:02 -07:00
Eina_Spinlock trash_lock ;
2013-09-11 00:08:06 -07:00
unsigned int trash_count ;
} objects ;
/* cached iterator for faster allocation cycle */
struct {
2013-10-10 01:26:02 -07:00
Eina_Trash * trash ;
Eina_Spinlock trash_lock ;
unsigned int trash_count ;
2013-09-11 00:08:06 -07:00
} iterators ;
2013-09-10 19:23:50 -07:00
2013-06-27 01:58:49 -07:00
unsigned int obj_size ; /**< size of an object of this class */
unsigned int base_id ;
unsigned int data_offset ; /* < Offset of the data within object data. */
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 ops_count ; /* < Offset of the data within object data. */
2013-06-27 01:58:49 -07:00
2018-06-29 08:31:10 -07:00
Eina_Thread construction_thread ; /** < the thread which called the class constructor */
2013-06-27 01:58:49 -07:00
Eina_Bool constructed : 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
Eina_Bool functions_set : 1 ;
2013-06-27 01:58:49 -07:00
/* [extensions*] + NULL */
/* [mro*] + NULL */
/* [extensions data offset] + NULL */
} ;
2013-09-23 02:07:07 -07:00
typedef struct
{
EINA_INLIST ;
const Eo * ref_obj ;
2017-02-14 20:42:29 -08:00
const char * data_klass ;
2013-09-23 02:07:07 -07:00
const char * file ;
int line ;
} Eo_Xref_Node ;
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
/* provide valgrind-like tracking of object allocationg and deletion */
void _eo_log_obj_report ( const Eo_Id id , int log_level , const char * func_name , const char * file , int line ) ;
2018-05-01 16:58:29 -07:00
void _efl_object_reuse ( _Eo_Object * obj ) ;
2016-10-21 07:02:27 -07:00
2013-09-27 03:13:14 -07:00
static inline
2015-05-28 08:49:13 -07:00
Eo * _eo_header_id_get ( const Eo_Header * header )
2013-09-27 03:13:14 -07:00
{
return ( Eo * ) header - > id ;
}
2016-09-07 01:53:33 -07:00
/* Retrieves the pointer to the object from the id */
2016-12-02 10:26:46 -08:00
_Eo_Object * _eo_obj_pointer_get ( const Eo_Id obj_id , const char * func_name , const char * file , int line ) ;
2016-09-07 01:53:33 -07:00
2013-09-27 03:13:14 -07:00
static inline
2016-08-10 07:23:04 -07:00
Efl_Class * _eo_class_id_get ( const _Efl_Class * klass )
2013-09-27 03:13:14 -07:00
{
2015-05-28 08:49:13 -07:00
return _eo_header_id_get ( ( Eo_Header * ) klass ) ;
2013-09-27 03:13:14 -07:00
}
static inline
2016-05-17 02:29:14 -07:00
Eo * _eo_obj_id_get ( const _Eo_Object * obj )
2013-09-27 03:13:14 -07:00
{
2015-05-28 08:49:13 -07:00
return _eo_header_id_get ( ( Eo_Header * ) obj ) ;
2013-09-27 03:13:14 -07:00
}
2013-06-27 01:58:49 -07:00
static inline void
2013-09-26 14:31:39 -07:00
_eo_condtor_reset ( _Eo_Object * obj )
2013-06-27 01:58:49 -07:00
{
obj - > condtor_done = EINA_FALSE ;
}
2018-05-12 22:14:53 -07:00
typedef struct _Efl_Object_Data Efl_Object_Data ;
EOLIAN void _efl_object_parent_set ( Eo * obj , Efl_Object_Data * pd , Eo * parent_id ) ;
2018-05-14 10:11:58 -07:00
void _efl_invalidate ( _Eo_Object * obj ) ;
2018-04-04 15:37:11 -07:00
2013-06-27 01:58:49 -07:00
static inline void
2016-12-02 10:26:46 -08:00
_efl_del_internal ( _Eo_Object * obj , const char * func_name , const char * file , int line )
2013-06-27 01:58:49 -07:00
{
/* We need that for the event callbacks that may ref/unref. */
obj - > refcount + + ;
2016-08-09 06:10:05 -07:00
const _Efl_Class * klass = obj - > klass ;
2013-06-27 01:58:49 -07:00
2018-05-12 22:14:53 -07:00
// If the object hasn't been invalidated yet, time to do it
2018-04-04 15:37:11 -07:00
// before any destructor kick in. This can happen when
// the object has no parent and get deleted by efl_unref.
2018-05-12 22:14:53 -07:00
if ( obj - > parent )
{
Eo * parent = efl_parent_get ( _eo_obj_id_get ( obj ) ) ;
ERR ( " Destructor path being taken while object [%s] still has a parent [%s] in state %i:%i. " ,
efl_debug_name_get ( _eo_obj_id_get ( obj ) ) ,
efl_debug_name_get ( parent ) ,
obj - > is_invalidating , obj - > invalidate ) ;
efl_parent_set ( _eo_obj_id_get ( obj ) , NULL ) ;
if ( obj - > parent )
{
CRI ( " Something is preventing [%s] from disconnecting from its parent, bypassing. " ,
efl_debug_name_get ( _eo_obj_id_get ( obj ) ) ) ;
_efl_object_parent_set ( _eo_obj_id_get ( obj ) , efl_data_scope_get ( _eo_obj_id_get ( obj ) , EFL_OBJECT_CLASS ) , NULL ) ;
}
}
2018-05-14 10:11:58 -07:00
else if ( ! obj - > invalidate | | ! obj - > is_invalidating )
{
_efl_invalidate ( obj ) ;
}
2018-04-04 15:37:11 -07:00
2016-08-09 06:10:05 -07:00
efl_event_callback_call ( _eo_obj_id_get ( obj ) , EFL_EVENT_DEL , NULL ) ;
2013-12-25 07:13:14 -08:00
2013-06-27 01:58:49 -07:00
_eo_condtor_reset ( obj ) ;
2016-08-09 06:10:05 -07:00
efl_destructor ( _eo_obj_id_get ( obj ) ) ;
2013-12-25 07:13:14 -08:00
2013-06-27 01:58:49 -07:00
if ( ! obj - > condtor_done )
{
2016-12-02 10:26:46 -08:00
ERR ( " in %s:%d: func '%s' Object of class '%s' - Not all of the object destructors have been executed. " ,
file , line , func_name , klass - > desc - > name ) ;
2013-06-27 01:58:49 -07:00
}
/*FIXME: add eo_class_unref(klass) ? - just to clear the caches. */
{
2014-06-13 10:09:56 -07:00
Eina_List * itr , * itr_n ;
Eo * emb_obj ;
2017-04-17 22:16:31 -07:00
EINA_LIST_FOREACH_SAFE ( obj - > opt - > composite_objects , itr , itr_n , emb_obj )
2013-06-27 01:58:49 -07:00
{
2016-08-09 06:10:05 -07:00
efl_composite_detach ( _eo_obj_id_get ( obj ) , emb_obj ) ;
2013-06-27 01:58:49 -07:00
}
}
2014-11-18 07:24:39 -08:00
obj - > destructed = EINA_TRUE ;
2013-06-27 01:58:49 -07:00
obj - > refcount - - ;
}
2016-05-19 03:33:17 -07:00
static inline Eina_Bool
_obj_is_override ( _Eo_Object * obj )
{
2017-04-17 22:16:31 -07:00
return obj - > opt - > vtable ! = NULL ;
2016-05-19 03:33:17 -07:00
}
2017-02-14 21:43:35 -08:00
void _eo_free ( _Eo_Object * obj , Eina_Bool manual_free ) ;
2013-06-27 01:58:49 -07:00
2013-09-26 14:31:39 -07:00
static inline _Eo_Object *
2016-08-15 06:44:41 -07:00
_efl_ref ( _Eo_Object * obj )
2013-06-27 01:58:49 -07:00
{
obj - > refcount + + ;
return obj ;
}
2016-12-02 10:26:46 -08:00
# define _efl_unref(obj) _efl_unref_internal(obj, __FUNCTION__, __FILE__, __LINE__)
2013-06-27 01:58:49 -07:00
static inline void
2016-12-02 10:26:46 -08:00
_efl_unref_internal ( _Eo_Object * obj , const char * func_name , const char * file , int line )
2013-06-27 01:58:49 -07:00
{
- - ( obj - > refcount ) ;
2015-10-15 09:51:20 -07:00
if ( EINA_UNLIKELY ( obj - > refcount < = 0 ) )
2013-06-27 01:58:49 -07:00
{
2018-05-14 14:47:07 -07:00
if ( obj - > user_refcount > 0 )
{
2018-05-15 13:27:23 -07:00
ERR ( " Object %p is still refcounted %i by users, but internal refcount reached 0. This should never happen. Please report a bug and send a backtrace to EFL developer. " , ( Eo * ) obj - > header . id , obj - > user_refcount ) ;
2018-05-14 14:47:07 -07:00
_eo_log_obj_report ( ( Eo_Id ) _eo_obj_id_get ( obj ) , EINA_LOG_LEVEL_ERR , __FUNCTION__ , __FILE__ , __LINE__ ) ;
return ;
}
2015-10-15 09:51:20 -07:00
if ( obj - > refcount < 0 )
{
2016-12-02 10:26:46 -08:00
ERR ( " in %s:%d: func '%s' Obj:%p. Refcount (%d) < 0. Too many unrefs. " , file , line , func_name , obj , obj - > refcount ) ;
2016-12-19 14:33:06 -08:00
_eo_log_obj_report ( ( Eo_Id ) _eo_obj_id_get ( obj ) , EINA_LOG_LEVEL_ERR , __FUNCTION__ , __FILE__ , __LINE__ ) ;
2015-10-15 09:51:20 -07:00
return ;
}
2014-12-04 17:19:47 -08:00
if ( obj - > destructed )
2013-06-27 01:58:49 -07:00
{
2016-12-02 10:26:46 -08:00
ERR ( " in %s:%d: func '%s' Object %p already destructed. " , file , line , func_name , _eo_obj_id_get ( obj ) ) ;
2016-12-19 14:33:06 -08:00
_eo_log_obj_report ( ( Eo_Id ) _eo_obj_id_get ( obj ) , EINA_LOG_LEVEL_ERR , __FUNCTION__ , __FILE__ , __LINE__ ) ;
2014-11-18 07:24:39 -08:00
return ;
}
2014-12-04 17:19:47 -08:00
if ( obj - > del_triggered )
2014-11-18 07:24:39 -08:00
{
2016-12-02 10:26:46 -08:00
ERR ( " in %s:%d: func '%s' Object %p deletion already triggered. You wrongly call efl_unref() within a destructor. " , file , line , func_name , _eo_obj_id_get ( obj ) ) ;
2016-12-19 14:33:06 -08:00
_eo_log_obj_report ( ( Eo_Id ) _eo_obj_id_get ( obj ) , EINA_LOG_LEVEL_ERR , __FUNCTION__ , __FILE__ , __LINE__ ) ;
2013-06-27 01:58:49 -07:00
return ;
}
2016-03-07 23:57:22 -08:00
2017-04-17 22:16:31 -07:00
if ( obj - > opt - > del_intercept )
2016-03-07 23:57:22 -08:00
{
2016-07-12 02:26:23 -07:00
Eo * obj_id = _eo_obj_id_get ( obj ) ;
2016-08-15 06:44:41 -07:00
efl_ref ( obj_id ) ;
2017-04-17 22:16:31 -07:00
obj - > opt - > del_intercept ( obj_id ) ;
2016-03-07 23:57:22 -08:00
return ;
}
2014-12-04 17:19:47 -08:00
obj - > del_triggered = EINA_TRUE ;
2013-06-27 01:58:49 -07:00
2016-12-02 10:26:46 -08:00
_efl_del_internal ( obj , func_name , file , line ) ;
2017-02-14 21:43:35 -08:00
if ( EINA_LIKELY ( ! obj - > manual_free ) )
2013-06-27 01:58:49 -07:00
{
2017-02-14 21:43:35 -08:00
# ifdef EO_DEBUG
/* If for some reason it's not empty, clear it. */
2017-02-14 20:42:29 -08:00
Eo * obj_id = _eo_obj_id_get ( obj ) ;
2017-02-14 21:43:35 -08:00
while ( obj - > xrefs )
2017-02-14 20:42:29 -08:00
{
2017-02-14 21:43:35 -08:00
Eina_Inlist * nitr = obj - > xrefs - > next ;
2019-02-11 09:07:15 -08:00
Eo_Xref_Node * xref = EINA_INLIST_CONTAINER_GET ( obj - > xrefs , Eo_Xref_Node ) ;
2017-02-14 21:43:35 -08:00
ERR ( " in %s:%d: func '%s' Object %p is still referenced by object %p. Origin: %s:%d " ,
file , line , func_name , obj_id , xref - > ref_obj , xref - > file , xref - > line ) ;
eina_freeq_ptr_main_add ( xref , free , sizeof ( * xref ) ) ;
obj - > xrefs = nitr ;
2017-02-14 20:42:29 -08:00
}
2017-02-14 21:43:35 -08:00
while ( obj - > data_xrefs )
2017-02-14 20:42:29 -08:00
{
2017-02-14 21:43:35 -08:00
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 ( " in %s:%d: func '%s' Object %p still has a reference to its own data (subclass: %s). Origin: %s:%d " ,
file , line , func_name , obj_id , xref - > data_klass , xref - > file , xref - > line ) ;
}
else
{
ERR ( " in %s:%d: func '%s' Data of object %p (subclass: %s) is still referenced by object %p. Origin: %s:%d " ,
file , line , func_name , 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 ;
2017-02-14 20:42:29 -08:00
}
2013-06-27 01:58:49 -07:00
# endif
2017-02-14 21:43:35 -08:00
_eo_free ( obj , EINA_FALSE ) ;
}
2013-06-27 01:58:49 -07:00
else
2016-08-15 06:44:41 -07:00
_efl_ref ( obj ) ; /* If we manual free, we keep a phantom ref. */
2013-06-27 01:58:49 -07:00
}
}
2013-04-18 04:19:02 -07:00
2012-05-01 00:40:14 -07:00
# endif