#ifndef _OBJ_H_ #define _OBJ_H_ #include #include #include #include #include #include #include "compat.h" #if 0 && defined(__DEBUG) #define OBJ_DEBUG 1 #else #define OBJ_DEBUG 0 #endif #if OBJ_DEBUG #define OBJ_BACKTRACE 1 #else #define OBJ_BACKTRACE 0 #endif #if OBJ_BACKTRACE #include #endif struct obj { #if OBJ_DEBUG uint32_t magic; char *type; #endif volatile gint ref; void (*free_func)(void *); unsigned int size; }; #if OBJ_DEBUG #define OBJ_MAGIC 0xf1eef1ee #define obj_alloc(t,a,b) __obj_alloc(a,b,t,__FILE__,__func__,__LINE__) #define obj_alloc0(t,a,b) __obj_alloc0(a,b,t,__FILE__,__func__,__LINE__) #define obj_hold(a) __obj_hold(&(a)->obj,__FILE__,__func__,__LINE__) #define obj_get(a) __obj_get(&(a)->obj,__FILE__,__func__,__LINE__) #define obj_put(a) __obj_put(&(a)->obj,__FILE__,__func__,__LINE__) #define obj_hold_o(a) __obj_hold(a,__FILE__,__func__,__LINE__) #define obj_get_o(a) __obj_get(a,__FILE__,__func__,__LINE__) #define obj_put_o(a) __obj_put(a,__FILE__,__func__,__LINE__) INLINE void __obj_init(struct obj *o, unsigned int size, void (*free_func)(void *), const char *type, const char *file, const char *func, unsigned int line); INLINE void *__obj_alloc(unsigned int size, void (*free_func)(void *), const char *type, const char *file, const char *func, unsigned int line); INLINE void *__obj_alloc0(unsigned int size, void (*free_func)(void *), const char *type, const char *file, const char *func, unsigned int line); INLINE struct obj *__obj_hold(struct obj *o, const char *file, const char *func, unsigned int line); INLINE void *__obj_get(struct obj *o, const char *file, const char *func, unsigned int line); INLINE void __obj_put(struct obj *o, const char *file, const char *func, unsigned int line); #else #define obj_alloc(t,a,b) __obj_alloc(a,b) #define obj_alloc0(t,a,b) __obj_alloc0(a,b) #define obj_hold(a) __obj_hold(&(a)->obj) #define obj_get(a) __obj_get(&(a)->obj) #define obj_put(a) __obj_put(&(a)->obj) #define obj_hold_o(a) __obj_hold(a) #define obj_get_o(a) __obj_get(a) #define obj_put_o(a) __obj_put(a) INLINE void __obj_init(struct obj *o, unsigned int size, void (*free_func)(void *)); INLINE void *__obj_alloc(unsigned int size, void (*free_func)(void *)); INLINE void *__obj_alloc0(unsigned int size, void (*free_func)(void *)); INLINE struct obj *__obj_hold(struct obj *o); INLINE void *__obj_get(struct obj *o); INLINE void __obj_put(struct obj *o); #endif #define obj_release(op) do { if (op) obj_put_o((struct obj *) op); op = NULL; } while (0) #include "log.h" INLINE void __obj_init(struct obj *o, unsigned int size, void (*free_func)(void *) #if OBJ_DEBUG , const char *type, const char *file, const char *func, unsigned int line #endif ) { #if OBJ_DEBUG o->magic = OBJ_MAGIC; o->type = strdup(type); write_log(LOG_DEBUG, "obj_allocX(\"%s\") -> %p [%s:%s:%u]", type, o, file, func, line); #if OBJ_BACKTRACE void *bt[4]; int addrs = backtrace(bt, 4); char **syms = backtrace_symbols(bt, addrs); if (syms) { for (int i = 0; i < addrs; i++) write_log(LOG_DEBUG, " obj_allocX caller %i: %s", i, syms[i]); } free(syms); #endif #endif o->ref = 1; o->free_func = free_func; o->size = size; } INLINE void *__obj_alloc(unsigned int size, void (*free_func)(void *) #if OBJ_DEBUG , const char *type, const char *file, const char *func, unsigned int line #endif ) { struct obj *r; r = g_slice_alloc(size); __obj_init(r, size, free_func #if OBJ_DEBUG , type, file, func, line #endif ); return r; } INLINE void *__obj_alloc0(unsigned int size, void (*free_func)(void *) #if OBJ_DEBUG , const char *type, const char *file, const char *func, unsigned int line #endif ) { struct obj *r; r = g_slice_alloc0(size); __obj_init(r, size, free_func #if OBJ_DEBUG , type, file, func, line #endif ); return r; } INLINE struct obj *__obj_hold(struct obj *o #if OBJ_DEBUG , const char *file, const char *func, unsigned int line #endif ) { #if OBJ_DEBUG assert(o->magic == OBJ_MAGIC); write_log(LOG_DEBUG, "obj_hold(%p, \"%s\"), refcnt inc %u -> %u [%s:%s:%u]", o, o->type, g_atomic_int_get(&o->ref), g_atomic_int_get(&o->ref) + 1, file, func, line); #if OBJ_BACKTRACE void *bt[4]; int addrs = backtrace(bt, 4); char **syms = backtrace_symbols(bt, addrs); if (syms) { for (int i = 0; i < addrs; i++) write_log(LOG_DEBUG, " obj_hold caller %i: %s", i, syms[i]); } free(syms); #endif #endif g_atomic_int_inc(&o->ref); return o; } INLINE void *__obj_get(struct obj *o #if OBJ_DEBUG , const char *file, const char *func, unsigned int line #endif ) { return __obj_hold(o #if OBJ_DEBUG , file, func, line #endif ); } INLINE void __obj_put(struct obj *o #if OBJ_DEBUG , const char *file, const char *func, unsigned int line #endif ) { #if OBJ_DEBUG assert(o->magic == OBJ_MAGIC); write_log(LOG_DEBUG, "obj_put(%p, \"%s\"), refcnt dec %u -> %u [%s:%s:%u]", o, o->type, g_atomic_int_get(&o->ref), g_atomic_int_get(&o->ref) - 1, file, func, line); #if OBJ_BACKTRACE void *bt[4]; int addrs = backtrace(bt, 4); char **syms = backtrace_symbols(bt, addrs); if (syms) { for (int i = 0; i < addrs; i++) write_log(LOG_DEBUG, " obj_put caller %i: %s", i, syms[i]); } free(syms); #endif #endif if (!g_atomic_int_dec_and_test(&o->ref)) return; if (o->free_func) o->free_func(o); #if OBJ_DEBUG o->magic = 0; if (o->type) free(o->type); #endif g_slice_free1(o->size, o); } #endif