Fix pbx_wilcalu from occupying 100% CPU now that it's nonblocking, and add malloc...
[asterisk/asterisk.git] / astmm.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Channel Variables
5  * 
6  * Copyright (C) 2002, Mark Spencer
7  *
8  * Mark Spencer <markster@linux-support.net>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14
15
16 #ifdef __AST_DEBUG_MALLOC
17
18 #include <malloc.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <pthread.h>
22 #include <asterisk/cli.h>
23
24 #define SOME_PRIME 563
25
26 #define FUNC_CALLOC             1
27 #define FUNC_MALLOC             2
28 #define FUNC_REALLOC    3
29 #define FUNC_STRDUP             4
30 #define FUNC_STRNDUP    5
31
32 /* Undefine all our macros */
33 #undef malloc
34 #undef calloc
35 #undef realloc
36 #undef strdup
37 #undef strndup
38 #undef free
39
40 static struct ast_region {
41         struct ast_region *next;
42         char file[40];
43         char func[40];
44         int lineno;
45         int which;
46         size_t len;
47         unsigned char data[0];
48 } *regions[SOME_PRIME];
49
50 #define HASH(a) \
51         (((unsigned long)(a)) % SOME_PRIME)
52         
53 static pthread_mutex_t reglock = PTHREAD_MUTEX_INITIALIZER;
54
55 static inline void *__ast_alloc_region(size_t size, int which, const char *file, int lineno, const char *func)
56 {
57         struct ast_region *reg;
58         void *ptr=NULL;
59         int hash;
60         reg = malloc(size + sizeof(struct ast_region));
61         pthread_mutex_lock(&reglock);
62         if (reg) {
63                 strncpy(reg->file, file, sizeof(reg->file) - 1);
64                 reg->file[sizeof(reg->file) - 1] = '\0';
65                 strncpy(reg->func, func, sizeof(reg->func) - 1);
66                 reg->func[sizeof(reg->func) - 1] = '\0';
67                 reg->lineno = lineno;
68                 reg->len = size;
69                 reg->which = which;
70                 ptr = reg->data;
71                 hash = HASH(ptr);
72                 reg->next = regions[hash];
73                 regions[hash] = reg;
74         }
75         pthread_mutex_unlock(&reglock);
76         if (!reg) {
77                 fprintf(stderr, "Out of memory :(\n");
78         }
79         return ptr;
80 }
81
82 static inline size_t __ast_sizeof_region(void *ptr)
83 {
84         int hash = HASH(ptr);
85         struct ast_region *reg;
86         size_t len = 0;
87         
88         pthread_mutex_lock(&reglock);
89         reg = regions[hash];
90         while(reg) {
91                 if (reg->data == ptr) {
92                         len = reg->len;
93                         break;
94                 }
95                 reg = reg->next;
96         }
97         pthread_mutex_unlock(&reglock);
98         return len;
99 }
100
101 static void __ast_free_region(void *ptr, const char *file, int lineno, const char *func)
102 {
103         int hash = HASH(ptr);
104         struct ast_region *reg, *prev = NULL;
105         pthread_mutex_lock(&reglock);
106         reg = regions[hash];
107         while(reg) {
108                 if (reg->data == ptr) {
109                         if (prev)
110                                 prev->next = reg->next;
111                         else
112                                 regions[hash] = reg->next;
113
114                         break;
115                 }
116                 prev = reg;
117                 reg = reg->next;
118         }
119         pthread_mutex_unlock(&reglock);
120         if (reg) {
121                 free(reg);
122         } else
123                 fprintf(stderr, "WARNING: Freeing unused memory at %p, in %s of %s, line %d\n",
124                         ptr, func, file, lineno);
125 }
126
127 void *__ast_calloc(size_t nmemb, size_t size, const char *file, int lineno, const char *func) 
128 {
129         void *ptr;
130         ptr = __ast_alloc_region(size * nmemb, FUNC_CALLOC, file, lineno, func);
131         if (ptr) 
132                 memset(ptr, 0, size * nmemb);
133         return ptr;
134 }
135
136 void *__ast_malloc(size_t size, const char *file, int lineno, const char *func) 
137 {
138         return __ast_alloc_region(size, FUNC_MALLOC, file, lineno, func);
139 }
140
141 void __ast_free(void *ptr, const char *file, int lineno, const char *func) 
142 {
143         __ast_free_region(ptr, file, lineno, func);
144 }
145
146 void *__ast_realloc(void *ptr, size_t size, const char *file, int lineno, const char *func) 
147 {
148         void *tmp;
149         size_t len=0;
150         if (ptr) {
151                 len = __ast_sizeof_region(ptr);
152                 if (!len) {
153                         fprintf(stderr, "WARNING: Realloc of unalloced memory at %p, in %s of %s, line %d\n",
154                                 ptr, func, file, lineno);
155                         return NULL;
156                 }
157         }
158         tmp = __ast_alloc_region(size, FUNC_REALLOC, file, lineno, func);
159         if (tmp) {
160                 if (len > size)
161                         len = size;
162                 if (ptr) {
163                         memcpy(tmp, ptr, len);
164                         __ast_free_region(ptr, file, lineno, func);
165                 }
166         }
167         return tmp;
168 }
169
170 char *__ast_strdup(const char *s, const char *file, int lineno, const char *func) 
171 {
172         size_t len;
173         void *ptr;
174         if (!s)
175                 return NULL;
176         len = strlen(s) + 1;
177         ptr = __ast_alloc_region(len, FUNC_STRDUP, file, lineno, func);
178         if (ptr)
179                 strcpy(ptr, s);
180         return ptr;
181 }
182
183 char *__ast_strndup(const char *s, size_t n, const char *file, int lineno, const char *func) 
184 {
185         size_t len;
186         void *ptr;
187         if (!s)
188                 return NULL;
189         len = strlen(s) + 1;
190         if (len > n)
191                 len = n;
192         ptr = __ast_alloc_region(len, FUNC_STRDUP, file, lineno, func);
193         if (ptr)
194                 strcpy(ptr, s);
195         return ptr;
196 }
197
198 static int handle_show_memory(int fd, int argc, char *argv[])
199 {
200         char *fn = NULL;
201         int x;
202         struct ast_region *reg;
203         unsigned int len=0;
204         int count = 0;
205         if (argc >3) 
206                 fn = argv[3];
207
208         /* try to lock applications list ... */
209         pthread_mutex_lock(&reglock);
210
211         for (x=0;x<SOME_PRIME;x++) {
212                 reg = regions[x];
213                 while(reg) {
214                         if (!fn || !strcasecmp(fn, reg->file)) {
215                                 ast_cli(fd, "%10d bytes allocated in %20s at line %5d of %s\n", reg->len, reg->func, reg->lineno, reg->file);
216                                 len += reg->len;
217                                 count++;
218                         }
219                         reg = reg->next;
220                 }
221         }
222         ast_cli(fd, "%d bytes allocated %d units total\n", len, count);
223         pthread_mutex_unlock(&reglock);
224         return RESULT_SUCCESS;
225 }
226
227 struct file_summary {
228         char fn[80];
229         int len;
230         int count;
231         struct file_summary *next;
232 };
233
234 static int handle_show_memory_summary(int fd, int argc, char *argv[])
235 {
236         char *fn = NULL;
237         int x;
238         struct ast_region *reg;
239         unsigned int len=0;
240         int count = 0;
241         struct file_summary *list = NULL, *cur;
242         
243         if (argc >3) 
244                 fn = argv[3];
245
246         /* try to lock applications list ... */
247         pthread_mutex_lock(&reglock);
248
249         for (x=0;x<SOME_PRIME;x++) {
250                 reg = regions[x];
251                 while(reg) {
252                         if (!fn || !strcasecmp(fn, reg->file)) {
253                                 cur = list;
254                                 while(cur) {
255                                         if ((!fn && !strcmp(cur->fn, reg->file)) || (fn && !strcmp(cur->fn, reg->func)))
256                                                 break;
257                                         cur = cur->next;
258                                 }
259                                 if (!cur) {
260                                         cur = alloca(sizeof(struct file_summary));
261                                         memset(cur, 0, sizeof(struct file_summary));
262                                         strncpy(cur->fn, fn ? reg->func : reg->file, sizeof(cur->fn) - 1);
263                                         cur->next = list;
264                                         list = cur;
265                                 }
266                                 cur->len += reg->len;
267                                 cur->count++;
268                         }
269                         reg = reg->next;
270                 }
271         }
272         pthread_mutex_unlock(&reglock);
273         
274         /* Dump the whole list */
275         while(list) {
276                 cur = list;
277                 len += list->len;
278                 count += list->count;
279                 if (fn)
280                         ast_cli(fd, "%10d bytes in %5d allocations in function '%s' of '%s'\n", list->len, list->count, list->fn, fn);
281                 else
282                         ast_cli(fd, "%10d bytes in %5d allocations in file '%s'\n", list->len, list->count, list->fn);
283                 list = list->next;
284 #if 0
285                 free(cur);
286 #endif          
287         }
288         ast_cli(fd, "%d bytes allocated %d units total\n", len, count);
289         return RESULT_SUCCESS;
290 }
291
292 static char show_memory_help[] = 
293 "Usage: show memory allocations [<file>]\n"
294 "       Dumps a list of all segments of allocated memory, optionally\n"
295 "limited to those from a specific file\n";
296
297 static char show_memory_summary_help[] = 
298 "Usage: show memory summary [<file>]\n"
299 "       Summarizes heap memory allocations by file, or optionally\n"
300 "by function, if a file is specified\n";
301
302 static struct ast_cli_entry show_memory_allocations_cli = 
303         { { "show", "memory", "allocations", NULL }, 
304         handle_show_memory, "Display outstanding memory allocations",
305         show_memory_help };
306
307 static struct ast_cli_entry show_memory_summary_cli = 
308         { { "show", "memory", "summary", NULL }, 
309         handle_show_memory_summary, "Summarize outstanding memory allocations",
310         show_memory_summary_help };
311
312
313 void __ast_mm_init(void)
314 {
315         ast_cli_register(&show_memory_allocations_cli);
316         ast_cli_register(&show_memory_summary_cli);
317 }
318
319 #endif