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