Add option to hide console connect messages
[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 /*! \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
42 #include "asterisk.h"
43 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
44
45 #include <pthread.h>
46 #include <sys/stat.h>
47 #include <signal.h>
48 #include <errno.h>
49 #include "asterisk/lock.h"
50 #include "asterisk/hashtab.h"
51 #include "asterisk/channel.h"
52 #include "asterisk/utils.h"
53 #include "asterisk/module.h"
54
55 struct rc_hist
56 {
57         char *desc;
58         struct rc_hist *next;
59 };
60
61 struct rc_obj /* short for refcounted object */
62 {
63         unsigned int addr;
64         unsigned int count;  /* this plus addr makes each entry unique, starts at 1 */
65         int last_count; /* count 1 objects will record how many other objects had the same addr */
66         int destroy_count;
67         int total_refcount;
68         struct rc_hist *hist;
69         struct rc_hist *last;
70 };
71
72 void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int cp2_size, size_t *used);
73 void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int cp2_size, size_t *used)
74 {
75 }
76
77 static unsigned int hashtab_hash_rc(const void *obj)
78 {
79         const struct rc_obj *rc = obj;
80         return rc->addr + rc->count; /* it's addr will make a FINE hash */
81 }
82
83 static int hashtab_compare_rc(const void *a, const void *b)
84 {
85         const struct rc_obj *rca = a;
86         const struct rc_obj *rcb = b;
87         if (rca->addr == rcb->addr && rca->count == rcb->count)
88                 return 0;
89         else
90                 return 1;
91 }
92
93
94 static struct rc_obj *alloc_obj(unsigned int addr, unsigned int count)
95 {
96         struct rc_obj *x = calloc(1,sizeof(struct rc_obj));
97         x->addr = addr;
98         x->count = count;
99         x->last_count = 1;
100         x->total_refcount = 1;
101         return x;
102 }
103
104 static void add_to_hist(char *buffer, struct rc_obj *obj)
105 {
106         struct rc_hist *y = calloc(1,sizeof(struct rc_hist));
107         y->desc = strdup(buffer);
108         if (obj->last) {
109                 obj->last->next = y;
110                 obj->last = y;
111         } else {
112                 obj->hist = obj->last = y;
113         }
114 }
115
116
117
118 int main(int argc,char **argv)
119 {
120         char linebuffer[300];
121         FILE *ifile = fopen("/tmp/refs", "r");
122         char *t;
123         unsigned int un;
124         struct rc_obj *curr_obj, *count1_obj;
125         struct rc_obj lookup;
126         struct ast_hashtab_iter *it;
127         struct ast_hashtab *objhash;
128         
129         if (!ifile) {
130                 printf("Sorry, Cannot open /tmp/refs!\n");
131                 exit(10);
132         }
133         
134         objhash = ast_hashtab_create(9000, hashtab_compare_rc, ast_hashtab_resize_java, ast_hashtab_newsize_java, hashtab_hash_rc, 1);
135         
136         while (fgets(linebuffer, sizeof(linebuffer), ifile)) {
137                 /* collect data about the entry */
138                 un = strtoul(linebuffer, &t, 16);
139                 lookup.addr = un;
140                 lookup.count = 1;
141
142                 count1_obj = ast_hashtab_lookup(objhash, &lookup);
143                 
144                 if (count1_obj) {
145                         /* there IS a count1 obj, so let's see which one we REALLY want */
146                         if (*(t+1) == '=') {
147                                 /* start a new object! */
148                                 curr_obj = alloc_obj(un, ++count1_obj->last_count);
149                                 /* put it in the hashtable */
150                                 ast_hashtab_insert_safe(objhash, curr_obj);
151                         } else {
152                                 if (count1_obj->last_count > 1) {
153                                         lookup.count = count1_obj->last_count;
154                                         curr_obj = ast_hashtab_lookup(objhash, &lookup);
155                                 } else {
156                                         curr_obj = count1_obj;
157                                 }
158                                 
159                         }
160
161                 } else {
162                         /* NO obj at ALL? -- better make one! */
163                         if (*(t+1) != '=') {
164                                 printf("BAD: object %x appears without previous allocation marker!\n", count1_obj->addr);
165                         }
166                         curr_obj = count1_obj = alloc_obj(un, 1);
167                         /* put it in the hashtable */
168                         ast_hashtab_insert_safe(objhash, curr_obj);
169                         
170                 }
171                 
172                 if (*(t+1) == '+' || *(t+1) == '-' ) {
173                         curr_obj->total_refcount += strtol(t+1, NULL, 10);
174                 } else if (*(t+1) == '*') {
175                         curr_obj->destroy_count++;
176                 }
177                 
178                 add_to_hist(linebuffer, curr_obj);
179         }
180         fclose(ifile);
181         
182         /* traverse the objects and check for problems */
183         it = ast_hashtab_start_traversal(objhash);
184         while ((curr_obj = ast_hashtab_next(it))) {
185                 if (curr_obj->total_refcount != 0 || curr_obj->destroy_count != 1) {
186                         struct rc_hist *h;
187                         if (curr_obj->total_refcount != 0)
188                                 printf("Problem: net Refcount not zero for object %x\n", curr_obj->addr);
189                         if (curr_obj->destroy_count > 1 )
190                                 printf("Problem: Object %x destroyed more than once!\n", curr_obj->addr);
191                         printf("Object %x history:\n", curr_obj->addr);
192                         for(h=curr_obj->hist;h;h=h->next) {
193                                 printf("   %s", h->desc);
194                         }
195                         printf("==============\n");
196                 }
197         }
198         ast_hashtab_end_traversal(it);
199         return 0;
200 }
201
202
203 /* stub routines to satisfy linking with asterisk subcomponents */
204
205 #ifndef LOW_MEMORY
206 int  ast_add_profile(const char *x, uint64_t scale)
207 {
208         return 0;
209 }
210 #endif
211
212 int ast_loader_register(int (*updater)(void))
213 {
214         return 1;
215 }
216
217 int ast_loader_unregister(int (*updater)(void))
218 {
219         return 1;
220 }
221 void ast_module_register(const struct ast_module_info *x)
222 {
223 }
224
225 void ast_module_unregister(const struct ast_module_info *x)
226 {
227 }
228
229 #ifndef LOW_MEMORY
230 void ast_register_file_version(const char *file, const char *version)
231 {
232 }
233
234 void ast_unregister_file_version(const char *file)
235 {
236
237 }
238
239 #undef ast_mark
240
241 int64_t ast_mark(int x, int start1_stop0)
242 {
243         return 0;
244 }
245 #endif
246
247 void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
248 {
249         va_list vars;
250         va_start(vars,fmt);
251         printf("LOG: lev:%d file:%s  line:%d func: %s  ",
252                    level, file, line, function);
253         vprintf(fmt, vars);
254         fflush(stdout);
255         va_end(vars);
256 }
257
258 void __ast_verbose(const char *file, int line, const char *func, const char *fmt, ...)
259 {
260         va_list vars;
261         va_start(vars,fmt);
262
263         printf("VERBOSE: ");
264         vprintf(fmt, vars);
265         fflush(stdout);
266         va_end(vars);
267 }
268
269 void ast_register_thread(char *name)
270 {
271
272 }
273
274 void ast_unregister_thread(void *id)
275 {
276 }
277 #ifdef HAVE_BKTR
278 struct ast_bt *ast_bt_create(void);
279 struct ast_bt *ast_bt_create(void) 
280 {
281         return NULL;
282 }
283
284 int ast_bt_get_addresses(struct ast_bt *bt);
285 int ast_bt_get_addresses(struct ast_bt *bt)
286 {
287         return 0;
288 }
289
290 void *ast_bt_destroy(struct ast_bt *bt);
291 void *ast_bt_destroy(struct ast_bt *bt)
292 {
293         return NULL;
294 }
295 #endif