Add some more hold music
[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 <time.h>
22 #include <asterisk/cli.h>
23 #include <asterisk/logger.h>
24 #include <asterisk/options.h>
25 #include <asterisk/lock.h>
26
27 #define SOME_PRIME 563
28
29 #define FUNC_CALLOC             1
30 #define FUNC_MALLOC             2
31 #define FUNC_REALLOC    3
32 #define FUNC_STRDUP             4
33 #define FUNC_STRNDUP    5
34 #define FUNC_VASPRINTF  6
35
36 /* Undefine all our macros */
37 #undef malloc
38 #undef calloc
39 #undef realloc
40 #undef strdup
41 #undef strndup
42 #undef free
43 #undef vasprintf
44
45 static FILE *mmlog;
46
47 static struct ast_region {
48         struct ast_region *next;
49         char file[40];
50         char func[40];
51         int lineno;
52         int which;
53         size_t len;
54         unsigned char data[0];
55 } *regions[SOME_PRIME];
56
57 #define HASH(a) \
58         (((unsigned long)(a)) % SOME_PRIME)
59         
60 AST_MUTEX_DEFINE_STATIC(reglock);
61 AST_MUTEX_DEFINE_STATIC(showmemorylock);
62
63 static inline void *__ast_alloc_region(size_t size, int which, const char *file, int lineno, const char *func)
64 {
65         struct ast_region *reg;
66         void *ptr=NULL;
67         int hash;
68         reg = malloc(size + sizeof(struct ast_region));
69         ast_mutex_lock(&reglock);
70         if (reg) {
71                 strncpy(reg->file, file, sizeof(reg->file) - 1);
72                 reg->file[sizeof(reg->file) - 1] = '\0';
73                 strncpy(reg->func, func, sizeof(reg->func) - 1);
74                 reg->func[sizeof(reg->func) - 1] = '\0';
75                 reg->lineno = lineno;
76                 reg->len = size;
77                 reg->which = which;
78                 ptr = reg->data;
79                 hash = HASH(ptr);
80                 reg->next = regions[hash];
81                 regions[hash] = reg;
82         }
83         ast_mutex_unlock(&reglock);
84         if (!reg) {
85                 fprintf(stderr, "Out of memory :(\n");
86                 if (mmlog) {
87                         fprintf(mmlog, "%ld - Out of memory\n", time(NULL));
88                         fflush(mmlog);
89                 }
90         }
91         return ptr;
92 }
93
94 static inline size_t __ast_sizeof_region(void *ptr)
95 {
96         int hash = HASH(ptr);
97         struct ast_region *reg;
98         size_t len = 0;
99         
100         ast_mutex_lock(&reglock);
101         reg = regions[hash];
102         while(reg) {
103                 if (reg->data == ptr) {
104                         len = reg->len;
105                         break;
106                 }
107                 reg = reg->next;
108         }
109         ast_mutex_unlock(&reglock);
110         return len;
111 }
112
113 static void __ast_free_region(void *ptr, const char *file, int lineno, const char *func)
114 {
115         int hash = HASH(ptr);
116         struct ast_region *reg, *prev = NULL;
117         ast_mutex_lock(&reglock);
118         reg = regions[hash];
119         while(reg) {
120                 if (reg->data == ptr) {
121                         if (prev)
122                                 prev->next = reg->next;
123                         else
124                                 regions[hash] = reg->next;
125
126                         break;
127                 }
128                 prev = reg;
129                 reg = reg->next;
130         }
131         ast_mutex_unlock(&reglock);
132         if (reg) {
133                 free(reg);
134         } else {
135                 fprintf(stderr, "WARNING: Freeing unused memory at %p, in %s of %s, line %d\n",
136                         ptr, func, file, lineno);
137                 if (mmlog) {
138                         fprintf(mmlog, "%ld - WARNING: Freeing unused memory at %p, in %s of %s, line %d\n", time(NULL),
139                         ptr, func, file, lineno);
140                         fflush(mmlog);
141                 }
142         }
143 }
144
145 void *__ast_calloc(size_t nmemb, size_t size, const char *file, int lineno, const char *func) 
146 {
147         void *ptr;
148         ptr = __ast_alloc_region(size * nmemb, FUNC_CALLOC, file, lineno, func);
149         if (ptr) 
150                 memset(ptr, 0, size * nmemb);
151         return ptr;
152 }
153
154 void *__ast_malloc(size_t size, const char *file, int lineno, const char *func) 
155 {
156         return __ast_alloc_region(size, FUNC_MALLOC, file, lineno, func);
157 }
158
159 void __ast_free(void *ptr, const char *file, int lineno, const char *func) 
160 {
161         __ast_free_region(ptr, file, lineno, func);
162 }
163
164 void *__ast_realloc(void *ptr, size_t size, const char *file, int lineno, const char *func) 
165 {
166         void *tmp;
167         size_t len=0;
168         if (ptr) {
169                 len = __ast_sizeof_region(ptr);
170                 if (!len) {
171                         fprintf(stderr, "WARNING: Realloc of unalloced memory at %p, in %s of %s, line %d\n",
172                                 ptr, func, file, lineno);
173                         if (mmlog) {
174                                 fprintf(mmlog, "%ld - WARNING: Realloc of unalloced memory at %p, in %s of %s, line %d\n",
175                                         time(NULL), ptr, func, file, lineno);
176                                 fflush(mmlog);
177                         }
178                         return NULL;
179                 }
180         }
181         tmp = __ast_alloc_region(size, FUNC_REALLOC, file, lineno, func);
182         if (tmp) {
183                 if (len > size)
184                         len = size;
185                 if (ptr) {
186                         memcpy(tmp, ptr, len);
187                         __ast_free_region(ptr, file, lineno, func);
188                 }
189         }
190         return tmp;
191 }
192
193 char *__ast_strdup(const char *s, const char *file, int lineno, const char *func) 
194 {
195         size_t len;
196         void *ptr;
197         if (!s)
198                 return NULL;
199         len = strlen(s) + 1;
200         ptr = __ast_alloc_region(len, FUNC_STRDUP, file, lineno, func);
201         if (ptr)
202                 strcpy(ptr, s);
203         return ptr;
204 }
205
206 char *__ast_strndup(const char *s, size_t n, const char *file, int lineno, const char *func) 
207 {
208         size_t len;
209         void *ptr;
210         if (!s)
211                 return NULL;
212         len = strlen(s) + 1;
213         if (len > n)
214                 len = n;
215         ptr = __ast_alloc_region(len, FUNC_STRNDUP, file, lineno, func);
216         if (ptr)
217                 strcpy(ptr, s);
218         return ptr;
219 }
220
221 int __ast_vasprintf(char **strp, const char *fmt, va_list ap, const char *file, int lineno, const char *func) 
222 {
223         int n, size = strlen(fmt) + 1;
224         if ((*strp = __ast_alloc_region(size, FUNC_VASPRINTF, file, lineno, func)) == NULL)
225                 return -1; 
226         for (;;) {
227                 n = vsnprintf(*strp, size, fmt, ap);
228                 if (n > -1 && n < size)
229                         return n;
230                 if (n > -1)     /* glibc 2.1 */
231                         size = n+1;
232                 else            /* glibc 2.0 */
233                         size *= 2;
234                 if ((*strp = __ast_realloc(*strp, size, file, lineno, func)) == NULL)
235                         return -1;
236         }
237 }
238
239 static int handle_show_memory(int fd, int argc, char *argv[])
240 {
241         char *fn = NULL;
242         int x;
243         struct ast_region *reg;
244         unsigned int len=0;
245         int count = 0;
246         if (argc >3) 
247                 fn = argv[3];
248
249         /* try to lock applications list ... */
250         ast_mutex_lock(&showmemorylock);
251
252         for (x=0;x<SOME_PRIME;x++) {
253                 reg = regions[x];
254                 while(reg) {
255                         if (!fn || !strcasecmp(fn, reg->file)) {
256                                 ast_cli(fd, "%10d bytes allocated in %20s at line %5d of %s\n", reg->len, reg->func, reg->lineno, reg->file);
257                                 len += reg->len;
258                                 count++;
259                         }
260                         reg = reg->next;
261                 }
262         }
263         ast_cli(fd, "%d bytes allocated %d units total\n", len, count);
264         ast_mutex_unlock(&showmemorylock);
265         return RESULT_SUCCESS;
266 }
267
268 struct file_summary {
269         char fn[80];
270         int len;
271         int count;
272         struct file_summary *next;
273 };
274
275 static int handle_show_memory_summary(int fd, int argc, char *argv[])
276 {
277         char *fn = NULL;
278         int x;
279         struct ast_region *reg;
280         unsigned int len=0;
281         int count = 0;
282         struct file_summary *list = NULL, *cur;
283         
284         if (argc >3) 
285                 fn = argv[3];
286
287         /* try to lock applications list ... */
288         ast_mutex_lock(&reglock);
289
290         for (x=0;x<SOME_PRIME;x++) {
291                 reg = regions[x];
292                 while(reg) {
293                         if (!fn || !strcasecmp(fn, reg->file)) {
294                                 cur = list;
295                                 while(cur) {
296                                         if ((!fn && !strcmp(cur->fn, reg->file)) || (fn && !strcmp(cur->fn, reg->func)))
297                                                 break;
298                                         cur = cur->next;
299                                 }
300                                 if (!cur) {
301                                         cur = alloca(sizeof(struct file_summary));
302                                         memset(cur, 0, sizeof(struct file_summary));
303                                         strncpy(cur->fn, fn ? reg->func : reg->file, sizeof(cur->fn) - 1);
304                                         cur->next = list;
305                                         list = cur;
306                                 }
307                                 cur->len += reg->len;
308                                 cur->count++;
309                         }
310                         reg = reg->next;
311                 }
312         }
313         ast_mutex_unlock(&reglock);
314         
315         /* Dump the whole list */
316         while(list) {
317                 cur = list;
318                 len += list->len;
319                 count += list->count;
320                 if (fn)
321                         ast_cli(fd, "%10d bytes in %5d allocations in function '%s' of '%s'\n", list->len, list->count, list->fn, fn);
322                 else
323                         ast_cli(fd, "%10d bytes in %5d allocations in file '%s'\n", list->len, list->count, list->fn);
324                 list = list->next;
325 #if 0
326                 free(cur);
327 #endif          
328         }
329         ast_cli(fd, "%d bytes allocated %d units total\n", len, count);
330         return RESULT_SUCCESS;
331 }
332
333 static char show_memory_help[] = 
334 "Usage: show memory allocations [<file>]\n"
335 "       Dumps a list of all segments of allocated memory, optionally\n"
336 "limited to those from a specific file\n";
337
338 static char show_memory_summary_help[] = 
339 "Usage: show memory summary [<file>]\n"
340 "       Summarizes heap memory allocations by file, or optionally\n"
341 "by function, if a file is specified\n";
342
343 static struct ast_cli_entry show_memory_allocations_cli = 
344         { { "show", "memory", "allocations", NULL }, 
345         handle_show_memory, "Display outstanding memory allocations",
346         show_memory_help };
347
348 static struct ast_cli_entry show_memory_summary_cli = 
349         { { "show", "memory", "summary", NULL }, 
350         handle_show_memory_summary, "Summarize outstanding memory allocations",
351         show_memory_summary_help };
352
353
354 void __ast_mm_init(void)
355 {
356         ast_cli_register(&show_memory_allocations_cli);
357         ast_cli_register(&show_memory_summary_cli);
358         mmlog = fopen("/var/log/asterisk/mmlog", "a+");
359         if (option_verbose)
360                 ast_verbose("Asterisk Malloc Debugger Started (see /var/log/asterisk/mmlog)\n");
361         if (mmlog) {
362                 fprintf(mmlog, "%ld - New session\n", time(NULL));
363                 fflush(mmlog);
364         }
365 }
366
367 #endif