2005-02-07 05:51:09 -08:00
|
|
|
/*
|
|
|
|
* vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
|
|
|
|
*/
|
2004-11-24 19:37:45 -08:00
|
|
|
#include "e.h"
|
|
|
|
|
|
|
|
/* TODO List:
|
|
|
|
*
|
|
|
|
* * fix a lot of parts of e17's code to use e_object_del NOT e_object_unref.
|
|
|
|
* there is a subtle difference. unref means u had a reference and you stop
|
|
|
|
* referencing the object - thats ALL. if you created it and now literally
|
|
|
|
* want to destroy it - del is the way to go. there is a separate handler for
|
|
|
|
* this so on del it can go and clean up objects that may reference this one
|
|
|
|
* etc.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* yes - i know. glibc specific... but i like being able to do my own */
|
|
|
|
/* backtraces! NB: you need CFLAGS="-rdynamic -g" LDFLAGS="-rdynamic -g" */
|
|
|
|
#ifdef OBJECT_PARANOIA_CHECK
|
|
|
|
#include <execinfo.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <setjmp.h>
|
|
|
|
|
|
|
|
/* local subsystem functions */
|
|
|
|
static void _e_object_segv(int sig);
|
|
|
|
|
|
|
|
/* local subsystem globals */
|
|
|
|
static sigjmp_buf _e_object_segv_buf;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* externally accessible functions */
|
|
|
|
void *
|
2005-01-21 22:58:34 -08:00
|
|
|
e_object_alloc(int size, int type, E_Object_Cleanup_Func cleanup_func)
|
2004-11-24 19:37:45 -08:00
|
|
|
{
|
|
|
|
E_Object *obj;
|
|
|
|
|
|
|
|
obj = calloc(1, size);
|
2004-12-22 22:38:27 -08:00
|
|
|
if (!obj) return NULL;
|
2004-11-24 19:37:45 -08:00
|
|
|
obj->magic = E_OBJECT_MAGIC;
|
2005-01-21 22:58:34 -08:00
|
|
|
obj->type = type;
|
2004-11-24 19:37:45 -08:00
|
|
|
obj->references = 1;
|
|
|
|
obj->cleanup_func = cleanup_func;
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
e_object_del(E_Object *obj)
|
|
|
|
{
|
|
|
|
E_OBJECT_CHECK(obj);
|
2005-01-13 05:55:00 -08:00
|
|
|
if (obj->deleted) return;
|
2005-01-12 01:22:44 -08:00
|
|
|
if (obj->del_att_func) obj->del_att_func(obj);
|
2005-06-28 00:59:13 -07:00
|
|
|
if (obj->del_func) obj->del_func(obj);
|
2005-01-13 05:55:00 -08:00
|
|
|
obj->deleted = 1;
|
2004-11-24 19:37:45 -08:00
|
|
|
e_object_unref(obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2005-05-11 06:13:43 -07:00
|
|
|
e_object_is_del(E_Object *obj)
|
2004-11-24 19:37:45 -08:00
|
|
|
{
|
|
|
|
E_OBJECT_CHECK_RETURN(obj, 1);
|
|
|
|
return obj->deleted;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
e_object_del_func_set(E_Object *obj, E_Object_Cleanup_Func del_func)
|
|
|
|
{
|
|
|
|
E_OBJECT_CHECK(obj);
|
|
|
|
obj->del_func = del_func;
|
|
|
|
}
|
|
|
|
|
2005-01-12 08:03:09 -08:00
|
|
|
void
|
|
|
|
e_object_type_set(E_Object *obj, int type)
|
|
|
|
{
|
|
|
|
E_OBJECT_CHECK(obj);
|
|
|
|
obj->type = type;
|
|
|
|
}
|
|
|
|
|
2004-11-24 19:37:45 -08:00
|
|
|
void
|
|
|
|
e_object_free(E_Object *obj)
|
|
|
|
{
|
|
|
|
E_OBJECT_CHECK(obj);
|
2005-07-27 21:35:45 -07:00
|
|
|
/*
|
2005-06-28 00:59:13 -07:00
|
|
|
if (obj->crumbs)
|
|
|
|
{
|
|
|
|
printf("EEEK obj type %x has crumbs still! ->\n", obj->type);
|
|
|
|
e_object_breadcrumb_debug(obj);
|
|
|
|
}
|
2005-07-27 21:35:45 -07:00
|
|
|
*/
|
2005-01-12 01:22:44 -08:00
|
|
|
if (obj->free_att_func) obj->free_att_func(obj);
|
2004-11-24 19:37:45 -08:00
|
|
|
obj->magic = E_OBJECT_MAGIC_FREED;
|
|
|
|
obj->cleanup_func(obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
e_object_ref(E_Object *obj)
|
|
|
|
{
|
2005-01-03 14:04:04 -08:00
|
|
|
E_OBJECT_CHECK_RETURN(obj, -1);
|
2004-11-24 19:37:45 -08:00
|
|
|
obj->references++;
|
2004-12-22 22:38:27 -08:00
|
|
|
return obj->references;
|
2004-11-24 19:37:45 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
e_object_unref(E_Object *obj)
|
|
|
|
{
|
2004-12-22 22:38:27 -08:00
|
|
|
int ref;
|
|
|
|
|
2005-01-03 14:04:04 -08:00
|
|
|
E_OBJECT_CHECK_RETURN(obj, -1);
|
2004-11-24 19:37:45 -08:00
|
|
|
obj->references--;
|
2004-12-22 22:38:27 -08:00
|
|
|
ref = obj->references;
|
2005-01-13 06:24:24 -08:00
|
|
|
if (obj->references == 0) e_object_free(obj);
|
2004-12-22 22:38:27 -08:00
|
|
|
return ref;
|
2004-11-24 19:37:45 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
e_object_ref_get(E_Object *obj)
|
|
|
|
{
|
|
|
|
E_OBJECT_CHECK_RETURN(obj, 0);
|
|
|
|
return obj->references;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
e_object_error(E_Object *obj)
|
|
|
|
{
|
|
|
|
#ifdef OBJECT_PARANOIA_CHECK
|
|
|
|
char buf[4096];
|
|
|
|
char bt[8192];
|
|
|
|
void *trace[128];
|
|
|
|
char **messages = NULL;
|
|
|
|
int i, trace_num;
|
|
|
|
|
|
|
|
/* fetch stacktrace */
|
|
|
|
trace_num = backtrace(trace, 128);
|
|
|
|
messages = backtrace_symbols(trace, trace_num);
|
|
|
|
|
|
|
|
/* build stacktrace */
|
|
|
|
bt[0] = 0;
|
|
|
|
if (messages)
|
|
|
|
{
|
|
|
|
for (i = 1; i < trace_num; i++)
|
|
|
|
{
|
|
|
|
strcat(bt, messages[i]);
|
|
|
|
strcat(bt, "\n");
|
|
|
|
}
|
|
|
|
free(messages);
|
|
|
|
}
|
|
|
|
/* if NULL obj then dump stacktrace */
|
|
|
|
if (!obj)
|
|
|
|
{
|
|
|
|
snprintf(buf, sizeof(buf),
|
|
|
|
"Object is NULL.\n"
|
|
|
|
"%s",
|
|
|
|
bt);
|
|
|
|
}
|
|
|
|
/* if obj pointer is non NULL, actually try an access and see if we segv */
|
|
|
|
else if (obj)
|
|
|
|
{
|
|
|
|
struct sigaction act, oact;
|
|
|
|
int magic = 0, segv = 0;
|
|
|
|
|
|
|
|
/* setup segv handler */
|
|
|
|
act.sa_handler = _e_object_segv;
|
|
|
|
act.sa_flags = SA_RESETHAND;
|
|
|
|
sigemptyset(&act.sa_mask);
|
|
|
|
sigaction(SIGSEGV, &act, &oact);
|
|
|
|
/* set a longjump to be within this if statement. only called if we */
|
|
|
|
/* segfault */
|
|
|
|
if (sigsetjmp(_e_object_segv_buf, 1))
|
|
|
|
{
|
|
|
|
sigaction(SIGSEGV, &oact, NULL);
|
|
|
|
segv = 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* try access magic value */
|
|
|
|
magic = obj->magic;
|
|
|
|
/* if pointer is bogus we'd segv and so jump to the if() above */
|
|
|
|
/* contents, and thus reset segv handler and set segv flag. */
|
|
|
|
/* if not we just continue moving along here and reset handler */
|
|
|
|
sigaction(SIGSEGV, &oact, NULL);
|
|
|
|
}
|
|
|
|
/* if we segfaulted above... */
|
|
|
|
if (segv)
|
|
|
|
snprintf(buf, sizeof(buf),
|
|
|
|
"Object [%p] is an invalid/garbage pointer.\n"
|
|
|
|
"Segfault successfully avoided.\n"
|
|
|
|
"%s",
|
|
|
|
obj,
|
|
|
|
bt);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* valid ram then... if we freed this object before */
|
|
|
|
if (magic == E_OBJECT_MAGIC_FREED)
|
|
|
|
snprintf(buf, sizeof(buf),
|
|
|
|
"Object [%p] is already freed.\n"
|
|
|
|
"%s",
|
|
|
|
obj,
|
|
|
|
bt);
|
|
|
|
/* garbage magic value - pointer to non object */
|
|
|
|
else if (magic != E_OBJECT_MAGIC)
|
|
|
|
snprintf(buf, sizeof(buf),
|
|
|
|
"Object [%p] has garbage magic (%x).\n"
|
|
|
|
"%s",
|
|
|
|
obj, magic,
|
|
|
|
bt);
|
2005-01-12 05:59:01 -08:00
|
|
|
else if (obj->references < 0)
|
|
|
|
snprintf(buf, sizeof(buf),
|
|
|
|
"Object [%p] has negative references (%i).\n"
|
|
|
|
"%s",
|
|
|
|
obj, obj->references,
|
|
|
|
bt);
|
|
|
|
else if (obj->references > 100)
|
|
|
|
snprintf(buf, sizeof(buf),
|
|
|
|
"Object [%p] has unusually high reference count (%i).\n"
|
|
|
|
"%s",
|
|
|
|
obj, obj->references,
|
|
|
|
bt);
|
2004-11-24 19:37:45 -08:00
|
|
|
/* it's all ok! */
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* display actual error message */
|
|
|
|
e_error_message_show("%s", buf);
|
|
|
|
// abort();
|
|
|
|
return 1;
|
|
|
|
#else
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
e_object_data_set(E_Object *obj, void *data)
|
|
|
|
{
|
|
|
|
E_OBJECT_CHECK(obj);
|
|
|
|
obj->data = data;
|
|
|
|
}
|
|
|
|
|
|
|
|
void *
|
|
|
|
e_object_data_get(E_Object *obj)
|
|
|
|
{
|
|
|
|
E_OBJECT_CHECK_RETURN(obj, NULL);
|
|
|
|
return obj->data;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
e_object_free_attach_func_set(E_Object *obj, void (*func) (void *obj))
|
|
|
|
{
|
|
|
|
E_OBJECT_CHECK(obj);
|
2005-01-12 01:22:44 -08:00
|
|
|
obj->free_att_func = func;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
e_object_del_attach_func_set(E_Object *obj, void (*func) (void *obj))
|
|
|
|
{
|
|
|
|
E_OBJECT_CHECK(obj);
|
|
|
|
obj->del_att_func = func;
|
2004-11-24 19:37:45 -08:00
|
|
|
}
|
|
|
|
|
2005-07-27 21:35:45 -07:00
|
|
|
/*
|
2005-06-24 23:54:22 -07:00
|
|
|
void
|
|
|
|
e_object_breadcrumb_add(E_Object *obj, char *crumb)
|
|
|
|
{
|
|
|
|
E_OBJECT_CHECK(obj);
|
|
|
|
obj->crumbs = evas_list_append(obj->crumbs, strdup(crumb));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
e_object_breadcrumb_del(E_Object *obj, char *crumb)
|
|
|
|
{
|
|
|
|
Evas_List *l;
|
|
|
|
|
|
|
|
E_OBJECT_CHECK(obj);
|
|
|
|
for (l = obj->crumbs; l; l = l->next)
|
|
|
|
{
|
|
|
|
if (!strcmp(crumb, l->data))
|
|
|
|
{
|
|
|
|
free(l->data);
|
|
|
|
obj->crumbs = evas_list_remove_list(obj->crumbs, l);
|
2005-06-28 00:15:51 -07:00
|
|
|
return;
|
2005-06-24 23:54:22 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
e_object_breadcrumb_debug(E_Object *obj)
|
|
|
|
{
|
|
|
|
Evas_List *l;
|
|
|
|
|
|
|
|
E_OBJECT_CHECK(obj);
|
|
|
|
for (l = obj->crumbs; l; l = l->next)
|
|
|
|
printf("CRUMB: %s\n", l->data);
|
|
|
|
}
|
2005-07-27 21:35:45 -07:00
|
|
|
*/
|
2005-06-24 23:54:22 -07:00
|
|
|
|
2004-11-24 19:37:45 -08:00
|
|
|
#ifdef OBJECT_PARANOIA_CHECK
|
|
|
|
/* local subsystem functions */
|
|
|
|
static void
|
|
|
|
_e_object_segv(int sig)
|
|
|
|
{
|
|
|
|
siglongjmp(_e_object_segv_buf, 1);
|
|
|
|
}
|
|
|
|
#endif
|