diff options
Diffstat (limited to 'utils/refcounter.c')
-rw-r--r-- | utils/refcounter.c | 268 |
1 files changed, 268 insertions, 0 deletions
diff --git a/utils/refcounter.c b/utils/refcounter.c new file mode 100644 index 000000000..4c3e96e3b --- /dev/null +++ b/utils/refcounter.c @@ -0,0 +1,268 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2008, Steve Murphy + * + * Steve Murphy <murf@digium.com> + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ +/*! \file + * + * \brief A program to read in the /tmp/refs file generated + * by astobj2 code when the REF_DEBUG macro is defined. + * It will read in the file line by line, and + * sort the data out by object, and check to see + * if the refcounts balance to zero, and the object + * was destroyed just once. Any problems that are + * found are reported to stdout and the objects + * ref count history is printed out. If all is well, + * this program reads in the /tmp/refs file and + * generates no output. No news is good news. + * The contents of the /tmp/refs file looks like this: + * +0x84fd718 -1 astobj2.c:926:cd_cb_debug (deref object via container destroy) [@1] +0x84fd718 =1 chan_sip.c:19760:build_user (allocate a user struct) +0x84fd718 +1 chan_sip.c:21558:reload_config (link user into users table) [@1] +0x84fd718 -1 chan_sip.c:2376:unref_user (Unref the result of build_user. Now, the table link is the only one left.) [@2] +0x84fd718 **call destructor** astobj2.c:926:cd_cb_debug (deref object via container destroy) + * + * + * \author Steve Murphy <murf@digium.com> + */ + +#include "asterisk.h" +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include <pthread.h> +#include <sys/stat.h> +#include <signal.h> +#include <errno.h> +#include "asterisk/lock.h" +#include "asterisk/hashtab.h" +#include "asterisk/channel.h" +#include "asterisk/utils.h" +#include "asterisk/module.h" + +struct rc_hist +{ + char *desc; + struct rc_hist *next; +}; + +struct rc_obj /* short for refcounted object */ +{ + unsigned int addr; + unsigned int count; /* this plus addr makes each entry unique, starts at 1 */ + int last_count; /* count 1 objects will record how many other objects had the same addr */ + int destroy_count; + int total_refcount; + struct rc_hist *hist; + struct rc_hist *last; +}; + +static unsigned int hashtab_hash_rc(const void *obj) +{ + const struct rc_obj *rc = obj; + return rc->addr + rc->count; /* it's addr will make a FINE hash */ +} + +static int hashtab_compare_rc(const void *a, const void *b) +{ + const struct rc_obj *rca = a; + const struct rc_obj *rcb = b; + if (rca->addr == rcb->addr && rca->count == rcb->count) + return 0; + else + return 1; +} + + +static struct rc_obj *alloc_obj(unsigned int addr, unsigned int count) +{ + struct rc_obj *x = calloc(1,sizeof(struct rc_obj)); + x->addr = addr; + x->count = count; + x->last_count = 1; + x->total_refcount = 1; + return x; +} + +static void add_to_hist(char *buffer, struct rc_obj *obj) +{ + struct rc_hist *y = calloc(1,sizeof(struct rc_hist)); + y->desc = strdup(buffer); + if (obj->last) { + obj->last->next = y; + obj->last = y; + } else { + obj->hist = obj->last = y; + } +} + + + +int main(int argc,char **argv) +{ + char linebuffer[300]; + FILE *ifile = fopen("/tmp/refs", "r"); + char *t; + unsigned int un; + struct rc_obj *curr_obj, *count1_obj; + struct rc_obj lookup; + struct ast_hashtab_iter *it; + struct ast_hashtab *objhash; + + if (!ifile) { + printf("Sorry, Cannot open /tmp/refs!\n"); + exit(10); + } + + objhash = ast_hashtab_create(9000, hashtab_compare_rc, ast_hashtab_resize_java, ast_hashtab_newsize_java, hashtab_hash_rc, 1); + + while (fgets(linebuffer, sizeof(linebuffer), ifile)) { + /* collect data about the entry */ + un = strtoul(linebuffer, &t, 16); + lookup.addr = un; + lookup.count = 1; + + count1_obj = ast_hashtab_lookup(objhash, &lookup); + + if (count1_obj) { + /* there IS a count1 obj, so let's see which one we REALLY want */ + if (*(t+1) == '=') { + /* start a new object! */ + curr_obj = alloc_obj(un, ++count1_obj->last_count); + /* put it in the hashtable */ + ast_hashtab_insert_safe(objhash, curr_obj); + } else { + if (count1_obj->last_count > 1) { + lookup.count = count1_obj->last_count; + curr_obj = ast_hashtab_lookup(objhash, &lookup); + } else { + curr_obj = count1_obj; + } + + } + + } else { + /* NO obj at ALL? -- better make one! */ + if (*(t+1) != '=') { + printf("BAD: object %x appears without previous allocation marker!\n", count1_obj->addr); + } + curr_obj = count1_obj = alloc_obj(un, 1); + /* put it in the hashtable */ + ast_hashtab_insert_safe(objhash, curr_obj); + + } + + if (*(t+1) == '+' || *(t+1) == '-' ) { + curr_obj->total_refcount += strtol(t+1, NULL, 10); + } else if (*(t+1) == '*') { + curr_obj->destroy_count++; + } + + add_to_hist(linebuffer, curr_obj); + } + fclose(ifile); + + /* traverse the objects and check for problems */ + it = ast_hashtab_start_traversal(objhash); + while ((curr_obj = ast_hashtab_next(it))) { + if (curr_obj->total_refcount != 0 || curr_obj->destroy_count != 1) { + struct rc_hist *h; + if (curr_obj->total_refcount != 0) + printf("Problem: net Refcount not zero for object %x\n", curr_obj->addr); + if (curr_obj->destroy_count > 1 ) + printf("Problem: Object %x destroyed more than once!\n", curr_obj->addr); + printf("Object %x history:\n", curr_obj->addr); + for(h=curr_obj->hist;h;h=h->next) { + printf(" %s", h->desc); + } + printf("==============\n"); + } + } + ast_hashtab_end_traversal(it); + return 0; +} + + +/* stub routines to satisfy linking with asterisk subcomponents */ + +int ast_add_profile(const char *x, uint64_t scale) +{ + return 0; +} + +int ast_loader_register(int (*updater)(void)) +{ + return 1; +} + +int ast_loader_unregister(int (*updater)(void)) +{ + return 1; +} +void ast_module_register(const struct ast_module_info *x) +{ +} + +void ast_module_unregister(const struct ast_module_info *x) +{ +} + + +void ast_register_file_version(const char *file, const char *version) +{ +} + +void ast_unregister_file_version(const char *file) +{ + +} + +#undef ast_mark + +int64_t ast_mark(int x, int start1_stop0) +{ + return 0; +} + +void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...) +{ + va_list vars; + va_start(vars,fmt); + printf("LOG: lev:%d file:%s line:%d func: %s ", + level, file, line, function); + vprintf(fmt, vars); + fflush(stdout); + va_end(vars); +} + +void ast_verbose(const char *fmt, ...) +{ + va_list vars; + va_start(vars,fmt); + + printf("VERBOSE: "); + vprintf(fmt, vars); + fflush(stdout); + va_end(vars); +} + +void ast_register_thread(char *name) +{ + +} + +void ast_unregister_thread(void *id) +{ +} |