refcounter.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 2008, Steve Murphy
  5. *
  6. * Steve Murphy <murf@digium.com>
  7. *
  8. * See http://www.asterisk.org for more information about
  9. * the Asterisk project. Please do not directly contact
  10. * any of the maintainers of this project for assistance;
  11. * the project provides a web site, mailing lists and IRC
  12. * channels for your use.
  13. *
  14. * This program is free software, distributed under the terms of
  15. * the GNU General Public License Version 2. See the LICENSE file
  16. * at the top of the source tree.
  17. */
  18. /*! \file
  19. *
  20. * \brief A program to read in the /tmp/refs file generated
  21. * by astobj2 code when the REF_DEBUG macro is defined.
  22. * It will read in the file line by line, and
  23. * sort the data out by object, and check to see
  24. * if the refcounts balance to zero, and the object
  25. * was destroyed just once. Any problems that are
  26. * found are reported to stdout and the objects
  27. * ref count history is printed out. If all is well,
  28. * this program reads in the /tmp/refs file and
  29. * generates no output. No news is good news.
  30. * The contents of the /tmp/refs file looks like this:
  31. *
  32. 0x84fd718 -1 astobj2.c:926:cd_cb_debug (deref object via container destroy) [@1]
  33. 0x84fd718 =1 chan_sip.c:19760:build_user (allocate a user struct)
  34. 0x84fd718 +1 chan_sip.c:21558:reload_config (link user into users table) [@1]
  35. 0x84fd718 -1 chan_sip.c:2376:unref_user (Unref the result of build_user. Now, the table link is the only one left.) [@2]
  36. 0x84fd718 **call destructor** astobj2.c:926:cd_cb_debug (deref object via container destroy)
  37. *
  38. *
  39. * \author Steve Murphy <murf@digium.com>
  40. */
  41. /*** MODULEINFO
  42. <support_level>extended</support_level>
  43. ***/
  44. #include "asterisk.h"
  45. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  46. #include <pthread.h>
  47. #include <sys/stat.h>
  48. #include <signal.h>
  49. #include <errno.h>
  50. #include "asterisk/lock.h"
  51. #include "asterisk/hashtab.h"
  52. #include "asterisk/channel.h"
  53. #include "asterisk/utils.h"
  54. #include "asterisk/module.h"
  55. struct rc_hist
  56. {
  57. char *desc;
  58. struct rc_hist *next;
  59. };
  60. struct rc_obj /* short for refcounted object */
  61. {
  62. unsigned int addr;
  63. unsigned int count; /* this plus addr makes each entry unique, starts at 1 */
  64. int last_count; /* count 1 objects will record how many other objects had the same addr */
  65. int destroy_count;
  66. int total_refcount;
  67. struct rc_hist *hist;
  68. struct rc_hist *last;
  69. };
  70. void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int cp2_size, size_t *used);
  71. void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int cp2_size, size_t *used)
  72. {
  73. }
  74. static unsigned int hashtab_hash_rc(const void *obj)
  75. {
  76. const struct rc_obj *rc = obj;
  77. return rc->addr + rc->count; /* it's addr will make a FINE hash */
  78. }
  79. static int hashtab_compare_rc(const void *a, const void *b)
  80. {
  81. const struct rc_obj *rca = a;
  82. const struct rc_obj *rcb = b;
  83. if (rca->addr == rcb->addr && rca->count == rcb->count)
  84. return 0;
  85. else
  86. return 1;
  87. }
  88. static struct rc_obj *alloc_obj(unsigned int addr, unsigned int count)
  89. {
  90. struct rc_obj *x = calloc(1,sizeof(struct rc_obj));
  91. x->addr = addr;
  92. x->count = count;
  93. x->last_count = 1;
  94. x->total_refcount = 1;
  95. return x;
  96. }
  97. static void add_to_hist(char *buffer, struct rc_obj *obj)
  98. {
  99. struct rc_hist *y = calloc(1,sizeof(struct rc_hist));
  100. y->desc = strdup(buffer);
  101. if (obj->last) {
  102. obj->last->next = y;
  103. obj->last = y;
  104. } else {
  105. obj->hist = obj->last = y;
  106. }
  107. }
  108. int main(int argc,char **argv)
  109. {
  110. char linebuffer[300];
  111. FILE *ifile = fopen("/tmp/refs", "r");
  112. char *t;
  113. unsigned int un;
  114. struct rc_obj *curr_obj, *count1_obj;
  115. struct rc_obj lookup;
  116. struct ast_hashtab_iter *it;
  117. struct ast_hashtab *objhash;
  118. if (!ifile) {
  119. printf("Sorry, Cannot open /tmp/refs!\n");
  120. exit(10);
  121. }
  122. objhash = ast_hashtab_create(9000, hashtab_compare_rc, ast_hashtab_resize_java, ast_hashtab_newsize_java, hashtab_hash_rc, 1);
  123. while (fgets(linebuffer, sizeof(linebuffer), ifile)) {
  124. /* collect data about the entry */
  125. un = strtoul(linebuffer, &t, 16);
  126. lookup.addr = un;
  127. lookup.count = 1;
  128. count1_obj = ast_hashtab_lookup(objhash, &lookup);
  129. if (count1_obj) {
  130. /* there IS a count1 obj, so let's see which one we REALLY want */
  131. if (*(t+1) == '=') {
  132. /* start a new object! */
  133. curr_obj = alloc_obj(un, ++count1_obj->last_count);
  134. /* put it in the hashtable */
  135. ast_hashtab_insert_safe(objhash, curr_obj);
  136. } else {
  137. if (count1_obj->last_count > 1) {
  138. lookup.count = count1_obj->last_count;
  139. curr_obj = ast_hashtab_lookup(objhash, &lookup);
  140. } else {
  141. curr_obj = count1_obj;
  142. }
  143. }
  144. } else {
  145. /* NO obj at ALL? -- better make one! */
  146. if (*(t+1) != '=') {
  147. printf("BAD: object %x appears without previous allocation marker!\n", un);
  148. }
  149. curr_obj = count1_obj = alloc_obj(un, 1);
  150. /* put it in the hashtable */
  151. ast_hashtab_insert_safe(objhash, curr_obj);
  152. }
  153. if (*(t+1) == '+' || *(t+1) == '-' ) {
  154. curr_obj->total_refcount += strtol(t+1, NULL, 10);
  155. } else if (*(t+1) == '*') {
  156. curr_obj->destroy_count++;
  157. }
  158. add_to_hist(linebuffer, curr_obj);
  159. }
  160. fclose(ifile);
  161. /* traverse the objects and check for problems */
  162. it = ast_hashtab_start_traversal(objhash);
  163. while ((curr_obj = ast_hashtab_next(it))) {
  164. if (curr_obj->total_refcount != 0 || curr_obj->destroy_count != 1) {
  165. struct rc_hist *h;
  166. if (curr_obj->total_refcount != 0)
  167. printf("Problem: net Refcount not zero for object %x\n", curr_obj->addr);
  168. if (curr_obj->destroy_count > 1 )
  169. printf("Problem: Object %x destroyed more than once!\n", curr_obj->addr);
  170. printf("Object %x history:\n", curr_obj->addr);
  171. for(h=curr_obj->hist;h;h=h->next) {
  172. printf(" %s", h->desc);
  173. }
  174. printf("==============\n");
  175. }
  176. }
  177. ast_hashtab_end_traversal(it);
  178. return 0;
  179. }
  180. /* stub routines to satisfy linking with asterisk subcomponents */
  181. #ifndef LOW_MEMORY
  182. int ast_add_profile(const char *x, uint64_t scale)
  183. {
  184. return 0;
  185. }
  186. #endif
  187. int ast_loader_register(int (*updater)(void))
  188. {
  189. return 1;
  190. }
  191. int ast_loader_unregister(int (*updater)(void))
  192. {
  193. return 1;
  194. }
  195. void ast_module_register(const struct ast_module_info *x)
  196. {
  197. }
  198. void ast_module_unregister(const struct ast_module_info *x)
  199. {
  200. }
  201. #ifndef LOW_MEMORY
  202. void ast_register_file_version(const char *file, const char *version)
  203. {
  204. }
  205. void ast_unregister_file_version(const char *file)
  206. {
  207. }
  208. #undef ast_mark
  209. int64_t ast_mark(int x, int start1_stop0)
  210. {
  211. return 0;
  212. }
  213. #endif
  214. void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
  215. {
  216. va_list vars;
  217. va_start(vars,fmt);
  218. printf("LOG: lev:%d file:%s line:%d func: %s ",
  219. level, file, line, function);
  220. vprintf(fmt, vars);
  221. fflush(stdout);
  222. va_end(vars);
  223. }
  224. void __ast_verbose(const char *file, int line, const char *func, const char *fmt, ...)
  225. {
  226. va_list vars;
  227. va_start(vars,fmt);
  228. printf("VERBOSE: ");
  229. vprintf(fmt, vars);
  230. fflush(stdout);
  231. va_end(vars);
  232. }
  233. void ast_register_thread(char *name)
  234. {
  235. }
  236. void ast_unregister_thread(void *id)
  237. {
  238. }
  239. #ifdef HAVE_BKTR
  240. struct ast_bt *ast_bt_create(void);
  241. struct ast_bt *ast_bt_create(void)
  242. {
  243. return NULL;
  244. }
  245. int ast_bt_get_addresses(struct ast_bt *bt);
  246. int ast_bt_get_addresses(struct ast_bt *bt)
  247. {
  248. return 0;
  249. }
  250. char **ast_bt_get_symbols(void **addresses, size_t num_frames);
  251. char **ast_bt_get_symbols(void **addresses, size_t num_frames)
  252. {
  253. char **foo = calloc(num_frames, sizeof(char *) + 1);
  254. if (foo) {
  255. int i;
  256. for (i = 0; i < num_frames; i++) {
  257. foo[i] = (char *) foo + sizeof(char *) * num_frames;
  258. }
  259. }
  260. return foo;
  261. }
  262. void *ast_bt_destroy(struct ast_bt *bt);
  263. void *ast_bt_destroy(struct ast_bt *bt)
  264. {
  265. return NULL;
  266. }
  267. #endif