summaryrefslogtreecommitdiff
path: root/src/lib/eo/eo_private.h
blob: dd486b4fa0545506cfd52f4ff26918db26a409dd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
#ifndef _EO_PRIVATE_H
#define _EO_PRIVATE_H

#include <Eina.h>

#define EO_EINA_MAGIC 0xa186bc32
#define EO_EINA_MAGIC_STR "Eo"
#define EO_FREED_EINA_MAGIC 0xa186bb32
#define EO_FREED_EINA_MAGIC_STR "Eo - Freed object"
#define EO_CLASS_EINA_MAGIC 0xa186ba32
#define EO_CLASS_EINA_MAGIC_STR "Eo Class"

#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)


extern int _eo_log_dom;

#ifdef CRI
#undef CRI
#endif
#define CRI(...) EINA_LOG_DOM_CRIT(_eo_log_dom, __VA_ARGS__)

#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__)

typedef uintptr_t Eo_Id;
typedef struct _Eo_Class _Eo_Class;
typedef struct _Eo_Object _Eo_Object;
typedef struct _Eo_Base Eo_Base;

/* Retrieves the pointer to the object from the id */
static inline _Eo_Object *_eo_obj_pointer_get(const Eo_Id obj_id);

/* Allocates an entry for the given object */
static inline Eo_Id _eo_id_allocate(const _Eo_Object *obj);

/* Releases an entry by the object id */
static inline void _eo_id_release(const Eo_Id obj_id);

/* Free all the entries and the tables */
static inline void _eo_free_ids_tables(void);

void _eo_condtor_done(Eo *obj);

struct _Eo_Base
{
#ifndef HAVE_EO_ID
     EINA_MAGIC
#endif
     Eo_Id id;
};

struct _Eo_Object
{
     Eo_Base header;
     Eo *parent;
     Eina_List *children;
     const _Eo_Class *klass;
#ifdef EO_DEBUG
     Eina_Inlist *xrefs;
     Eina_Inlist *data_xrefs;
#endif

     const _Eo_Object **composites;

     int refcount;
     int datarefcount;

     Eina_Bool do_error:1;
     Eina_Bool condtor_done:1;

     Eina_Bool composite:1;
     Eina_Bool del:1;
     Eina_Bool manual_free:1;
     /* data [parents, self, mixins]*/
     /* [composite*] */
};

/* FIXME: Change the type to something generic that makes sense for eo */
typedef void (*eo_op_func_type)(Eo *, void *class_data, va_list *list);

typedef struct _Dich_Chain1 Dich_Chain1;

typedef struct
{
   eo_op_func_type func;
   const _Eo_Class *src;
} op_type_funcs;

struct _Dich_Chain1
{
   op_type_funcs *funcs;
};

typedef struct
{
   const _Eo_Class *klass;
   size_t offset;
} Eo_Extension_Data_Offset;

struct _Eo_Class
{
   Eo_Base header;

   const _Eo_Class *parent;
   const Eo_Class_Description *desc;
   Dich_Chain1 *chain; /**< The size is chain size */

   const _Eo_Class **extensions;

   Eo_Extension_Data_Offset *extn_data_off;

   const _Eo_Class **mro;

   /* cached object for faster allocation */
   struct {
      Eina_Trash  *trash;
      Eina_Spinlock    trash_lock;
      unsigned int trash_count;
   } objects;

   /* cached iterator for faster allocation cycle */
   struct {
      Eina_Trash   *trash;
      Eina_Spinlock trash_lock;
      unsigned int  trash_count;
   } iterators;

   unsigned int obj_size; /**< size of an object of this class */
   unsigned int chain_size;
   unsigned int base_id;
   unsigned int data_offset; /* < Offset of the data within object data. */
   unsigned int composites_count;

   Eina_Bool constructed : 1;
   /* [extensions*] + NULL */
   /* [mro*] + NULL */
   /* [extensions data offset] + NULL */
};

typedef struct
{
   EINA_INLIST;
   const Eo *ref_obj;
   const char *file;
   int line;
} Eo_Xref_Node;

static inline
Eo *_eo_header_id_get(const Eo_Base *header)
{
#ifdef HAVE_EO_ID
   return (Eo *) header->id;
#else
   return (Eo *) header;
#endif
}

static inline
Eo_Class *_eo_class_id_get(const _Eo_Class *klass)
{
   return _eo_header_id_get((Eo_Base *) klass);
}

static inline
Eo *_eo_id_get(const _Eo_Object *obj)
{
   return _eo_header_id_get((Eo_Base *) obj);
}

static inline void
_eo_condtor_reset(_Eo_Object *obj)
{
   obj->condtor_done = EINA_FALSE;
}

static inline void
_eo_del_internal(const char *file, int line, _Eo_Object *obj)
{
   Eina_Bool do_err;
   /* We need that for the event callbacks that may ref/unref. */
   obj->refcount++;

   const _Eo_Class *klass = obj->klass;

   eo_do(_eo_id_get(obj), eo_event_callback_call(EO_EV_DEL, NULL));

   _eo_condtor_reset(obj);

   do_err = EINA_FALSE;
   eo_do(_eo_id_get(obj), eo_destructor(););

   if (EINA_UNLIKELY(do_err))
     {
        ERR("in %s:%d: Object of class '%s' - One of the object destructors have failed.",
            file, line, klass->desc->name);
     }

   if (!obj->condtor_done)
     {
        ERR("in %s:%d: Object of class '%s' - Not all of the object destructors have been executed.",
            file, line, klass->desc->name);
     }
   /*FIXME: add eo_class_unref(klass) ? - just to clear the caches. */

     {
        const _Eo_Object **comp_itr = obj->composites;
        for (unsigned int i = 0; i < obj->klass->composites_count; i++, comp_itr++)
          {
             if (*comp_itr)
               eo_composite_detach(_eo_id_get(*comp_itr), _eo_id_get(obj));
          }
     }

   obj->del = EINA_TRUE;
   obj->refcount--;
}

static inline void
_eo_free(_Eo_Object *obj)
{
   _Eo_Class *klass = (_Eo_Class*) obj->klass;

#ifdef EO_DEBUG
   if (obj->datarefcount)
     {
        ERR("Object %p data still referenced %d time(s).", obj, obj->datarefcount);
     }
#endif
   _eo_id_release((Eo_Id) _eo_id_get(obj));

   eina_spinlock_take(&klass->objects.trash_lock);
   if (klass->objects.trash_count <= 8)
     {
        eina_trash_push(&klass->objects.trash, obj);
        klass->objects.trash_count++;
     }
   else
     {
        free(obj);
     }
   eina_spinlock_release(&klass->objects.trash_lock);
}

static inline _Eo_Object *
_eo_ref(_Eo_Object *obj)
{
   obj->refcount++;
   return obj;
}

static inline void
_eo_unref(_Eo_Object *obj)
{
   --(obj->refcount);
   if (obj->refcount == 0)
     {
        if (obj->del)
          {
             ERR("Object %p already deleted.", obj);
             return;
          }

        _eo_del_internal(__FILE__, __LINE__, obj);

#ifdef EO_DEBUG
        /* If for some reason it's not empty, clear it. */
        while (obj->xrefs)
          {
             ERR("obj->xrefs is not empty, possibly a bug, please report. - An error will be reported for each xref in the stack.");
             Eina_Inlist *nitr = obj->xrefs->next;
             free(EINA_INLIST_CONTAINER_GET(obj->xrefs, Eo_Xref_Node));
             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);
             ERR("Data of object 0x%lx is still referenced by object %p", (unsigned long) _eo_id_get(obj), xref->ref_obj);

             free(xref);
             obj->data_xrefs = nitr;
          }
#endif

        if (!obj->manual_free)
          _eo_free(obj);
        else
          _eo_ref(obj); /* If we manual free, we keep a phantom ref. */
     }
   else if (obj->refcount < 0)
     {
        ERR("Obj:%p. Refcount (%d) < 0. Too many unrefs.", obj, obj->refcount);
        return;
     }
}

#endif