1 #include "e.h"
2
3 /* yes - i know. glibc specific... but i like being able to do my own */
4 /* backtraces! NB: you need CFLAGS="-rdynamic -g" LDFLAGS="-rdynamic -g" */
5 #ifdef OBJECT_PARANOIA_CHECK
6
7 /* local subsystem functions */
8 static void _e_object_segv(int sig);
9
10 /* local subsystem globals */
11 static sigjmp_buf _e_object_segv_buf;
12 #endif
13
14 /* externally accessible functions */
15 E_API void *
e_object_alloc(int size,int type,E_Object_Cleanup_Func cleanup_func)16 e_object_alloc(int size, int type, E_Object_Cleanup_Func cleanup_func)
17 {
18 E_Object *obj;
19
20 obj = calloc(1, size);
21 if (!obj) return NULL;
22 obj->magic = E_OBJECT_MAGIC;
23 obj->type = type;
24 obj->references = 1;
25 obj->cleanup_func = cleanup_func;
26 return obj;
27 }
28
29 static void
_delay_del(void * data)30 _delay_del(void *data)
31 {
32 E_Object *obj = data;
33
34 obj->delay_del_job = NULL;
35 if (obj->del_att_func) obj->del_att_func(obj);
36 if (obj->del_func) obj->del_func(obj);
37 e_object_unref(obj);
38 }
39
40 E_API void
e_object_del(E_Object * obj)41 e_object_del(E_Object *obj)
42 {
43 E_OBJECT_CHECK(obj);
44 if (obj->deleted) return;
45 if (obj->del_delay_func)
46 {
47 if (obj->ref_debug)
48 INF("[%p] DELAY DEL (REF: %d)", obj, obj->references);
49 obj->del_delay_func(obj);
50 if (!obj->delay_del_job)
51 obj->delay_del_job = ecore_job_add(_delay_del, obj);
52 obj->deleted = 1;
53 return;
54 }
55 if (obj->ref_debug)
56 INF("[%p] DEL (REF: %d)", obj, obj->references);
57 obj->deleted = 1;
58 if (obj->del_att_func) obj->del_att_func(obj);
59 if (obj->del_func) obj->del_func(obj);
60 e_object_unref(obj);
61 }
62
63 E_API void
e_object_delay_del_set(E_Object * obj,void * func)64 e_object_delay_del_set(E_Object *obj, void *func)
65 {
66 E_OBJECT_CHECK(obj);
67 obj->del_delay_func = func;
68 }
69
70 E_API int
e_object_is_del(E_Object * obj)71 e_object_is_del(E_Object *obj)
72 {
73 E_OBJECT_CHECK_RETURN(obj, 1);
74 return obj->deleted;
75 }
76
77 E_API void
e_object_del_func_set(E_Object * obj,E_Object_Cleanup_Func del_func)78 e_object_del_func_set(E_Object *obj, E_Object_Cleanup_Func del_func)
79 {
80 E_OBJECT_CHECK(obj);
81 obj->del_func = del_func;
82 }
83
84 E_API void
e_object_type_set(E_Object * obj,int type)85 e_object_type_set(E_Object *obj, int type)
86 {
87 E_OBJECT_CHECK(obj);
88 obj->type = type;
89 }
90
91 E_API void
e_object_free(E_Object * obj)92 e_object_free(E_Object *obj)
93 {
94 E_OBJECT_CHECK(obj);
95 if (obj->free_att_func) obj->free_att_func(obj);
96 obj->free_att_func = NULL;
97 obj->walking_list++;
98 while (obj->del_fn_list)
99 {
100 E_Object_Delfn *dfn = (E_Object_Delfn *)obj->del_fn_list;
101 if (!dfn->delete_me) dfn->func(dfn->data, obj);
102 obj->del_fn_list = eina_inlist_remove(obj->del_fn_list,
103 EINA_INLIST_GET(dfn));
104 free(dfn);
105 }
106 obj->walking_list--;
107 if (obj->references) return;
108 /*
109 * FIXME:
110 * although this is good - if during cleanup the cleanup func calls
111 * other generic funcs to do cleanups on the same object... we get bitching.
112 * disable for now (the final free of the struct should probably happen after
113 * the cleanup func and be done by the object system - set the magic after
114 * cleanup :)
115 */
116 #if 0
117 obj->magic = E_OBJECT_MAGIC_FREED;
118 #endif
119 obj->cleanup_func(obj);
120 obj = NULL;
121 }
122
123 E_API int
e_object_ref(E_Object * obj)124 e_object_ref(E_Object *obj)
125 {
126 E_OBJECT_CHECK_RETURN(obj, -1);
127 obj->references++;
128 if (obj->ref_debug)
129 INF("[%p] REF (REF: %d)", obj, obj->references);
130 return obj->references;
131 }
132
133 E_API int
e_object_unref(E_Object * obj)134 e_object_unref(E_Object *obj)
135 {
136 int ref;
137
138 E_OBJECT_CHECK_RETURN(obj, -1);
139 if (!obj->references) return 0;
140 obj->references--;
141 ref = obj->references;
142 if (obj->ref_debug)
143 {
144 if ((ref > 1) && (ref < 1000))
145 INF("[%p] UNREF (REF: %d)", obj, ref);
146 else if (ref == 1)
147 INF("[%p] UNREF (REF: %d)", obj, ref);
148 else if (!ref)
149 INF("[%p] UNREF (REF: %d)", obj, ref);
150 else
151 CRI("[%p] UNREF (REF: %d)", obj, ref);
152 }
153 if (obj->references == 0) e_object_free(obj);
154 return ref;
155 }
156
157 E_API int
e_object_ref_get(E_Object * obj)158 e_object_ref_get(E_Object *obj)
159 {
160 E_OBJECT_CHECK_RETURN(obj, 0);
161 return obj->references;
162 }
163
164 #if 0
165 E_API void
166 e_bt(void)
167 {
168 int i, trace_num;
169 void *trace[128];
170 char **messages = NULL;
171 trace_num = backtrace(trace, 128);
172 messages = backtrace_symbols(trace, trace_num);
173 if (messages)
174 {
175 for (i = 1; i < trace_num; i++)
176 {
177 int j;
178
179 for (j = 1; j < i; j++)
180 putchar(' ');
181 printf("%s\n", messages[i]);
182 }
183 free(messages);
184 }
185 }
186
187 #endif
188
189 E_API int
e_object_error(E_Object * obj)190 e_object_error(E_Object *obj)
191 {
192 #ifdef OBJECT_PARANOIA_CHECK
193 char buf[4096];
194 char bt[8192];
195 void *trace[128];
196 char **messages = NULL;
197 int i, trace_num;
198
199 /* fetch stacktrace */
200 trace_num = backtrace(trace, 128);
201 messages = backtrace_symbols(trace, trace_num);
202
203 /* build stacktrace */
204 bt[0] = 0;
205 if (messages)
206 {
207 for (i = 1; i < trace_num; i++)
208 {
209 strcat(bt, messages[i]);
210 strcat(bt, "\n");
211 }
212 free(messages);
213 }
214 /* if NULL obj then dump stacktrace */
215 if (!obj)
216 {
217 snprintf(buf, sizeof(buf),
218 "Object is NULL.\n"
219 "%s",
220 bt);
221 }
222 /* if obj pointer is non NULL, actually try an access and see if we segv */
223 else if (obj)
224 {
225 struct sigaction act, oact;
226 int magic = 0, segv = 0;
227
228 /* setup segv handler */
229 act.sa_handler = _e_object_segv;
230 act.sa_flags = SA_RESETHAND;
231 sigemptyset(&act.sa_mask);
232 sigaction(SIGSEGV, &act, &oact);
233 /* set a longjump to be within this if statement. only called if we */
234 /* segfault */
235 if (sigsetjmp(_e_object_segv_buf, 1))
236 {
237 sigaction(SIGSEGV, &oact, NULL);
238 segv = 1;
239 }
240 else
241 {
242 /* try access magic value */
243 magic = obj->magic;
244 /* if pointer is bogus we'd segv and so jump to the if () above */
245 /* contents, and thus reset segv handler and set segv flag. */
246 /* if not we just continue moving along here and reset handler */
247 sigaction(SIGSEGV, &oact, NULL);
248 }
249 /* if we segfaulted above... */
250 if (segv)
251 snprintf(buf, sizeof(buf),
252 "Object [%p] is an invalid/garbage pointer.\n"
253 "Segfault successfully avoided.\n"
254 "%s",
255 obj,
256 bt);
257 else
258 {
259 /* valid ram then... if we freed this object before */
260 if (magic == E_OBJECT_MAGIC_FREED)
261 snprintf(buf, sizeof(buf),
262 "Object [%p] is already freed.\n"
263 "%s",
264 obj,
265 bt);
266 /* garbage magic value - pointer to non object */
267 else if (magic != E_OBJECT_MAGIC)
268 snprintf(buf, sizeof(buf),
269 "Object [%p] has garbage magic (%x).\n"
270 "%s",
271 obj, magic,
272 bt);
273 else if (obj->references < 0)
274 snprintf(buf, sizeof(buf),
275 "Object [%p] has negative references (%i).\n"
276 "%s",
277 obj, obj->references,
278 bt);
279 else if (obj->references > 100)
280 snprintf(buf, sizeof(buf),
281 "Object [%p] has unusually high reference count (%i).\n"
282 "%s",
283 obj, obj->references,
284 bt);
285 /* it's all ok! */
286 else
287 {
288 return 0;
289 }
290 }
291 }
292 /* display actual error message */
293 e_error_message_show("%s", buf);
294 return 1;
295 #else
296 if (!obj)
297 {
298 fprintf(stderr, "ERROR: Object is NULL. Add break point at %s:%d\n",
299 __FILE__, __LINE__);
300 return 1;
301 }
302 return 0;
303 #endif
304 }
305
306 E_API void
e_object_data_set(E_Object * obj,const void * data)307 e_object_data_set(E_Object *obj, const void *data)
308 {
309 E_OBJECT_CHECK(obj);
310 obj->data = (void *)data;
311 }
312
313 E_API void *
e_object_data_get(E_Object * obj)314 e_object_data_get(E_Object *obj)
315 {
316 E_OBJECT_CHECK_RETURN(obj, NULL);
317 return obj->data;
318 }
319
320 E_API void
e_object_free_attach_func_set(E_Object * obj,E_Object_Cleanup_Func func)321 e_object_free_attach_func_set(E_Object *obj, E_Object_Cleanup_Func func)
322 {
323 E_OBJECT_CHECK(obj);
324 obj->free_att_func = func;
325 }
326
327 E_API void
e_object_del_attach_func_set(E_Object * obj,E_Object_Cleanup_Func func)328 e_object_del_attach_func_set(E_Object *obj, E_Object_Cleanup_Func func)
329 {
330 E_OBJECT_CHECK(obj);
331 obj->del_att_func = func;
332 }
333
334 E_API void
e_object_ref_debug_set(E_Object * obj,Eina_Bool set)335 e_object_ref_debug_set(E_Object *obj, Eina_Bool set)
336 {
337 E_OBJECT_CHECK(obj);
338 obj->ref_debug = !!set;
339 }
340
341 E_API void
e_object_delfn_clear(E_Object * obj)342 e_object_delfn_clear(E_Object *obj)
343 {
344 E_Object_Delfn *dfn;
345
346 E_OBJECT_CHECK(obj);
347 if (obj->walking_list)
348 {
349 EINA_INLIST_FOREACH(obj->del_fn_list, dfn)
350 {
351 dfn->delete_me = 1;
352 }
353 return;
354 }
355 while (obj->del_fn_list)
356 {
357 dfn = (E_Object_Delfn *)obj->del_fn_list;
358 obj->del_fn_list = eina_inlist_remove(obj->del_fn_list,
359 EINA_INLIST_GET(dfn));
360 free(dfn);
361 }
362 }
363
364 E_API E_Object_Delfn *
e_object_delfn_add(E_Object * obj,void (* func)(void * data,void * obj),void * data)365 e_object_delfn_add(E_Object *obj, void (*func)(void *data, void *obj), void *data)
366 {
367 E_Object_Delfn *dfn;
368 E_OBJECT_CHECK_RETURN(obj, NULL);
369 dfn = calloc(1, sizeof(E_Object_Delfn));
370 if (!dfn) return NULL;
371 dfn->func = func;
372 dfn->data = data;
373 obj->del_fn_list = eina_inlist_append(obj->del_fn_list, EINA_INLIST_GET(dfn));
374 return dfn;
375 }
376
377 E_API void
e_object_delfn_del(E_Object * obj,E_Object_Delfn * dfn)378 e_object_delfn_del(E_Object *obj, E_Object_Delfn *dfn)
379 {
380 E_OBJECT_CHECK(obj);
381 if (obj->walking_list)
382 {
383 dfn->delete_me = 1;
384 return;
385 }
386 obj->del_fn_list = eina_inlist_remove(obj->del_fn_list, EINA_INLIST_GET(dfn));
387 free(dfn);
388 }
389
390 /*
391 void
392 e_object_breadcrumb_add(E_Object *obj, char *crumb)
393 {
394 E_OBJECT_CHECK(obj);
395 obj->crumbs = eina_list_append(obj->crumbs, strdup(crumb));
396 }
397
398 void
399 e_object_breadcrumb_del(E_Object *obj, char *crumb)
400 {
401 Eina_List *l;
402 char *key;
403
404 E_OBJECT_CHECK(obj);
405 EINA_LIST_FOREACH(obj->crumbs, l, key)
406 {
407 if (!strcmp(crumb, key))
408 {
409 free(key);
410 obj->crumbs = eina_list_remove_list(obj->crumbs, l);
411 return;
412 }
413 }
414 }
415
416 void
417 e_object_breadcrumb_debug(E_Object *obj)
418 {
419 Eina_List *l;
420 char *key;
421
422 E_OBJECT_CHECK(obj);
423 EINA_LISt_FOREACH(obj->crumbs, l, key)
424 printf("CRUMB: %s\n", key);
425 }
426 */
427
428 #ifdef OBJECT_PARANOIA_CHECK
429 /* local subsystem functions */
430 static void
_e_object_segv(int sig)431 _e_object_segv(int sig)
432 {
433 siglongjmp(_e_object_segv_buf, 1);
434 }
435
436 #endif
437