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
7 /* local subsystem functions */
8 static void _e_object_segv(int sig);
10 /* local subsystem globals */
11 static sigjmp_buf _e_object_segv_buf;
14 /* externally accessible functions */
16 e_object_alloc(int size, int type, E_Object_Cleanup_Func cleanup_func)
20 obj = calloc(1, size);
21 if (!obj) return NULL;
22 obj->magic = E_OBJECT_MAGIC;
25 obj->cleanup_func = cleanup_func;
30 e_object_del(E_Object *obj)
33 if (obj->deleted) return;
35 if (obj->del_att_func) obj->del_att_func(obj);
36 if (obj->del_func) obj->del_func(obj);
41 e_object_is_del(E_Object *obj)
43 E_OBJECT_CHECK_RETURN(obj, 1);
48 e_object_del_func_set(E_Object *obj, E_Object_Cleanup_Func del_func)
51 obj->del_func = del_func;
55 e_object_type_set(E_Object *obj, int type)
62 e_object_free(E_Object *obj)
65 if (obj->free_att_func) obj->free_att_func(obj);
66 obj->free_att_func = NULL;
68 while (obj->del_fn_list)
70 E_Object_Delfn *dfn = (E_Object_Delfn *)obj->del_fn_list;
71 if (!dfn->delete_me) dfn->func(dfn->data, obj);
72 obj->del_fn_list = eina_inlist_remove(obj->del_fn_list,
73 EINA_INLIST_GET(dfn));
77 if (obj->references) return;
80 * although this is good - if during cleanup the cleanup func calls
81 * other generic funcs to do cleanups on the same object... we get bitching.
82 * disable for now (the final free of the struct should probably happen after
83 * the cleanup func and be done by the object system - set the magic after
87 obj->magic = E_OBJECT_MAGIC_FREED;
89 obj->cleanup_func(obj);
93 e_object_ref(E_Object *obj)
95 E_OBJECT_CHECK_RETURN(obj, -1);
97 return obj->references;
101 e_object_unref(E_Object *obj)
105 E_OBJECT_CHECK_RETURN(obj, -1);
106 if (!obj->references) return 0;
108 ref = obj->references;
109 if (obj->references == 0) e_object_free(obj);
114 e_object_ref_get(E_Object *obj)
116 E_OBJECT_CHECK_RETURN(obj, 0);
117 return obj->references;
126 char **messages = NULL;
127 trace_num = backtrace(trace, 128);
128 messages = backtrace_symbols(trace, trace_num);
131 for (i = 1; i < trace_num; i++)
135 for (j = 1; j < i; j++) putchar(' ');
136 printf("%s\n", messages[i]);
144 e_object_error(E_Object *obj)
146 #ifdef OBJECT_PARANOIA_CHECK
150 char **messages = NULL;
153 /* fetch stacktrace */
154 trace_num = backtrace(trace, 128);
155 messages = backtrace_symbols(trace, trace_num);
157 /* build stacktrace */
161 for (i = 1; i < trace_num; i++)
163 strcat(bt, messages[i]);
168 /* if NULL obj then dump stacktrace */
171 snprintf(buf, sizeof(buf),
176 /* if obj pointer is non NULL, actually try an access and see if we segv */
179 struct sigaction act, oact;
180 int magic = 0, segv = 0;
182 /* setup segv handler */
183 act.sa_handler = _e_object_segv;
184 act.sa_flags = SA_RESETHAND;
185 sigemptyset(&act.sa_mask);
186 sigaction(SIGSEGV, &act, &oact);
187 /* set a longjump to be within this if statement. only called if we */
189 if (sigsetjmp(_e_object_segv_buf, 1))
191 sigaction(SIGSEGV, &oact, NULL);
196 /* try access magic value */
198 /* if pointer is bogus we'd segv and so jump to the if () above */
199 /* contents, and thus reset segv handler and set segv flag. */
200 /* if not we just continue moving along here and reset handler */
201 sigaction(SIGSEGV, &oact, NULL);
203 /* if we segfaulted above... */
205 snprintf(buf, sizeof(buf),
206 "Object [%p] is an invalid/garbage pointer.\n"
207 "Segfault successfully avoided.\n"
213 /* valid ram then... if we freed this object before */
214 if (magic == E_OBJECT_MAGIC_FREED)
215 snprintf(buf, sizeof(buf),
216 "Object [%p] is already freed.\n"
220 /* garbage magic value - pointer to non object */
221 else if (magic != E_OBJECT_MAGIC)
222 snprintf(buf, sizeof(buf),
223 "Object [%p] has garbage magic (%x).\n"
227 else if (obj->references < 0)
228 snprintf(buf, sizeof(buf),
229 "Object [%p] has negative references (%i).\n"
231 obj, obj->references,
233 else if (obj->references > 100)
234 snprintf(buf, sizeof(buf),
235 "Object [%p] has unusually high reference count (%i).\n"
237 obj, obj->references,
246 /* display actual error message */
247 e_error_message_show("%s", buf);
252 fprintf(stderr, "ERROR: Object is NULL. Add break point at %s:%d\n",
261 e_object_data_set(E_Object *obj, const void *data)
264 obj->data = (void*)data;
268 e_object_data_get(E_Object *obj)
270 E_OBJECT_CHECK_RETURN(obj, NULL);
275 e_object_free_attach_func_set(E_Object *obj, E_Object_Cleanup_Func func)
278 obj->free_att_func = func;
282 e_object_del_attach_func_set(E_Object *obj, E_Object_Cleanup_Func func)
285 obj->del_att_func = func;
289 e_object_delfn_clear(E_Object *obj)
292 while (obj->del_fn_list)
294 E_Object_Delfn *dfn = (E_Object_Delfn *)obj->del_fn_list;
295 if (obj->walking_list)
299 obj->del_fn_list = eina_inlist_remove(obj->del_fn_list,
300 EINA_INLIST_GET(dfn));
306 EAPI E_Object_Delfn *
307 e_object_delfn_add(E_Object *obj, void (*func) (void *data, void *obj), void *data)
310 E_OBJECT_CHECK_RETURN(obj, NULL);
311 dfn = calloc(1, sizeof(E_Object_Delfn));
312 if (!dfn) return NULL;
315 obj->del_fn_list = eina_inlist_append(obj->del_fn_list, EINA_INLIST_GET(dfn));
320 e_object_delfn_del(E_Object *obj, E_Object_Delfn *dfn)
323 if (obj->walking_list)
328 obj->del_fn_list = eina_inlist_remove(obj->del_fn_list, EINA_INLIST_GET(dfn));
334 e_object_breadcrumb_add(E_Object *obj, char *crumb)
337 obj->crumbs = eina_list_append(obj->crumbs, strdup(crumb));
341 e_object_breadcrumb_del(E_Object *obj, char *crumb)
347 EINA_LIST_FOREACH(obj->crumbs, l, key)
349 if (!strcmp(crumb, key))
352 obj->crumbs = eina_list_remove_list(obj->crumbs, l);
359 e_object_breadcrumb_debug(E_Object *obj)
365 EINA_LISt_FOREACH(obj->crumbs, l, key)
366 printf("CRUMB: %s\n", key);
370 #ifdef OBJECT_PARANOIA_CHECK
371 /* local subsystem functions */
373 _e_object_segv(int sig)
375 siglongjmp(_e_object_segv_buf, 1);