Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals

astmm.c

Go to the documentation of this file.
00001 /* 00002 * Asterisk -- A telephony toolkit for Linux. 00003 * 00004 * Channel Variables 00005 * 00006 * Copyright (C) 2002, Mark Spencer 00007 * 00008 * Mark Spencer <markster@linux-support.net> 00009 * 00010 * This program is free software, distributed under the terms of 00011 * the GNU General Public License 00012 */ 00013 00014 00015 00016 #ifdef __AST_DEBUG_MALLOC 00017 00018 #include <malloc.h> 00019 #include <stdio.h> 00020 #include <string.h> 00021 #include <pthread.h> 00022 #include <time.h> 00023 #include <asterisk/cli.h> 00024 #include <asterisk/logger.h> 00025 #include <asterisk/options.h> 00026 #include <asterisk/lock.h> 00027 00028 #define SOME_PRIME 563 00029 00030 #define FUNC_CALLOC 1 00031 #define FUNC_MALLOC 2 00032 #define FUNC_REALLOC 3 00033 #define FUNC_STRDUP 4 00034 #define FUNC_STRNDUP 5 00035 #define FUNC_VASPRINTF 6 00036 00037 /* Undefine all our macros */ 00038 #undef malloc 00039 #undef calloc 00040 #undef realloc 00041 #undef strdup 00042 #undef strndup 00043 #undef free 00044 #undef vasprintf 00045 00046 static FILE *mmlog; 00047 00048 static struct ast_region { 00049 struct ast_region *next; 00050 char file[40]; 00051 char func[40]; 00052 int lineno; 00053 int which; 00054 size_t len; 00055 unsigned char data[0]; 00056 } *regions[SOME_PRIME]; 00057 00058 #define HASH(a) \ 00059 (((unsigned long)(a)) % SOME_PRIME) 00060 00061 AST_MUTEX_DEFINE_STATIC(reglock); 00062 AST_MUTEX_DEFINE_STATIC(showmemorylock); 00063 00064 static inline void *__ast_alloc_region(size_t size, int which, const char *file, int lineno, const char *func) 00065 { 00066 struct ast_region *reg; 00067 void *ptr=NULL; 00068 int hash; 00069 reg = malloc(size + sizeof(struct ast_region)); 00070 ast_mutex_lock(&reglock); 00071 if (reg) { 00072 strncpy(reg->file, file, sizeof(reg->file) - 1); 00073 reg->file[sizeof(reg->file) - 1] = '\0'; 00074 strncpy(reg->func, func, sizeof(reg->func) - 1); 00075 reg->func[sizeof(reg->func) - 1] = '\0'; 00076 reg->lineno = lineno; 00077 reg->len = size; 00078 reg->which = which; 00079 ptr = reg->data; 00080 hash = HASH(ptr); 00081 reg->next = regions[hash]; 00082 regions[hash] = reg; 00083 } 00084 ast_mutex_unlock(&reglock); 00085 if (!reg) { 00086 fprintf(stderr, "Out of memory :(\n"); 00087 if (mmlog) { 00088 fprintf(mmlog, "%ld - Out of memory\n", time(NULL)); 00089 fflush(mmlog); 00090 } 00091 } 00092 return ptr; 00093 } 00094 00095 static inline size_t __ast_sizeof_region(void *ptr) 00096 { 00097 int hash = HASH(ptr); 00098 struct ast_region *reg; 00099 size_t len = 0; 00100 00101 ast_mutex_lock(&reglock); 00102 reg = regions[hash]; 00103 while(reg) { 00104 if (reg->data == ptr) { 00105 len = reg->len; 00106 break; 00107 } 00108 reg = reg->next; 00109 } 00110 ast_mutex_unlock(&reglock); 00111 return len; 00112 } 00113 00114 static void __ast_free_region(void *ptr, const char *file, int lineno, const char *func) 00115 { 00116 int hash = HASH(ptr); 00117 struct ast_region *reg, *prev = NULL; 00118 ast_mutex_lock(&reglock); 00119 reg = regions[hash]; 00120 while(reg) { 00121 if (reg->data == ptr) { 00122 if (prev) 00123 prev->next = reg->next; 00124 else 00125 regions[hash] = reg->next; 00126 00127 break; 00128 } 00129 prev = reg; 00130 reg = reg->next; 00131 } 00132 ast_mutex_unlock(&reglock); 00133 if (reg) { 00134 free(reg); 00135 } else { 00136 fprintf(stderr, "WARNING: Freeing unused memory at %p, in %s of %s, line %d\n", 00137 ptr, func, file, lineno); 00138 if (mmlog) { 00139 fprintf(mmlog, "%ld - WARNING: Freeing unused memory at %p, in %s of %s, line %d\n", time(NULL), 00140 ptr, func, file, lineno); 00141 fflush(mmlog); 00142 } 00143 } 00144 } 00145 00146 void *__ast_calloc(size_t nmemb, size_t size, const char *file, int lineno, const char *func) 00147 { 00148 void *ptr; 00149 ptr = __ast_alloc_region(size * nmemb, FUNC_CALLOC, file, lineno, func); 00150 if (ptr) 00151 memset(ptr, 0, size * nmemb); 00152 return ptr; 00153 } 00154 00155 void *__ast_malloc(size_t size, const char *file, int lineno, const char *func) 00156 { 00157 return __ast_alloc_region(size, FUNC_MALLOC, file, lineno, func); 00158 } 00159 00160 void __ast_free(void *ptr, const char *file, int lineno, const char *func) 00161 { 00162 __ast_free_region(ptr, file, lineno, func); 00163 } 00164 00165 void *__ast_realloc(void *ptr, size_t size, const char *file, int lineno, const char *func) 00166 { 00167 void *tmp; 00168 size_t len=0; 00169 if (ptr) { 00170 len = __ast_sizeof_region(ptr); 00171 if (!len) { 00172 fprintf(stderr, "WARNING: Realloc of unalloced memory at %p, in %s of %s, line %d\n", 00173 ptr, func, file, lineno); 00174 if (mmlog) { 00175 fprintf(mmlog, "%ld - WARNING: Realloc of unalloced memory at %p, in %s of %s, line %d\n", 00176 time(NULL), ptr, func, file, lineno); 00177 fflush(mmlog); 00178 } 00179 return NULL; 00180 } 00181 } 00182 tmp = __ast_alloc_region(size, FUNC_REALLOC, file, lineno, func); 00183 if (tmp) { 00184 if (len > size) 00185 len = size; 00186 if (ptr) { 00187 memcpy(tmp, ptr, len); 00188 __ast_free_region(ptr, file, lineno, func); 00189 } 00190 } 00191 return tmp; 00192 } 00193 00194 char *__ast_strdup(const char *s, const char *file, int lineno, const char *func) 00195 { 00196 size_t len; 00197 void *ptr; 00198 if (!s) 00199 return NULL; 00200 len = strlen(s) + 1; 00201 ptr = __ast_alloc_region(len, FUNC_STRDUP, file, lineno, func); 00202 if (ptr) 00203 strcpy(ptr, s); 00204 return ptr; 00205 } 00206 00207 char *__ast_strndup(const char *s, size_t n, const char *file, int lineno, const char *func) 00208 { 00209 size_t len; 00210 void *ptr; 00211 if (!s) 00212 return NULL; 00213 len = strlen(s) + 1; 00214 if (len > n) 00215 len = n; 00216 ptr = __ast_alloc_region(len, FUNC_STRNDUP, file, lineno, func); 00217 if (ptr) 00218 strcpy(ptr, s); 00219 return ptr; 00220 } 00221 00222 int __ast_vasprintf(char **strp, const char *fmt, va_list ap, const char *file, int lineno, const char *func) 00223 { 00224 int n, size = strlen(fmt) + 1; 00225 if ((*strp = __ast_alloc_region(size, FUNC_VASPRINTF, file, lineno, func)) == NULL) 00226 return -1; 00227 for (;;) { 00228 n = vsnprintf(*strp, size, fmt, ap); 00229 if (n > -1 && n < size) 00230 return n; 00231 if (n > -1) /* glibc 2.1 */ 00232 size = n+1; 00233 else /* glibc 2.0 */ 00234 size *= 2; 00235 if ((*strp = __ast_realloc(*strp, size, file, lineno, func)) == NULL) 00236 return -1; 00237 } 00238 } 00239 00240 static int handle_show_memory(int fd, int argc, char *argv[]) 00241 { 00242 char *fn = NULL; 00243 int x; 00244 struct ast_region *reg; 00245 unsigned int len=0; 00246 int count = 0; 00247 if (argc >3) 00248 fn = argv[3]; 00249 00250 /* try to lock applications list ... */ 00251 ast_mutex_lock(&showmemorylock); 00252 00253 for (x=0;x<SOME_PRIME;x++) { 00254 reg = regions[x]; 00255 while(reg) { 00256 if (!fn || !strcasecmp(fn, reg->file)) { 00257 ast_cli(fd, "%10d bytes allocated in %20s at line %5d of %s\n", reg->len, reg->func, reg->lineno, reg->file); 00258 len += reg->len; 00259 count++; 00260 } 00261 reg = reg->next; 00262 } 00263 } 00264 ast_cli(fd, "%d bytes allocated %d units total\n", len, count); 00265 ast_mutex_unlock(&showmemorylock); 00266 return RESULT_SUCCESS; 00267 } 00268 00269 struct file_summary { 00270 char fn[80]; 00271 int len; 00272 int count; 00273 struct file_summary *next; 00274 }; 00275 00276 static int handle_show_memory_summary(int fd, int argc, char *argv[]) 00277 { 00278 char *fn = NULL; 00279 int x; 00280 struct ast_region *reg; 00281 unsigned int len=0; 00282 int count = 0; 00283 struct file_summary *list = NULL, *cur; 00284 00285 if (argc >3) 00286 fn = argv[3]; 00287 00288 /* try to lock applications list ... */ 00289 ast_mutex_lock(&reglock); 00290 00291 for (x=0;x<SOME_PRIME;x++) { 00292 reg = regions[x]; 00293 while(reg) { 00294 if (!fn || !strcasecmp(fn, reg->file)) { 00295 cur = list; 00296 while(cur) { 00297 if ((!fn && !strcmp(cur->fn, reg->file)) || (fn && !strcmp(cur->fn, reg->func))) 00298 break; 00299 cur = cur->next; 00300 } 00301 if (!cur) { 00302 cur = alloca(sizeof(struct file_summary)); 00303 memset(cur, 0, sizeof(struct file_summary)); 00304 strncpy(cur->fn, fn ? reg->func : reg->file, sizeof(cur->fn) - 1); 00305 cur->next = list; 00306 list = cur; 00307 } 00308 cur->len += reg->len; 00309 cur->count++; 00310 } 00311 reg = reg->next; 00312 } 00313 } 00314 ast_mutex_unlock(&reglock); 00315 00316 /* Dump the whole list */ 00317 while(list) { 00318 cur = list; 00319 len += list->len; 00320 count += list->count; 00321 if (fn) 00322 ast_cli(fd, "%10d bytes in %5d allocations in function '%s' of '%s'\n", list->len, list->count, list->fn, fn); 00323 else 00324 ast_cli(fd, "%10d bytes in %5d allocations in file '%s'\n", list->len, list->count, list->fn); 00325 list = list->next; 00326 #if 0 00327 free(cur); 00328 #endif 00329 } 00330 ast_cli(fd, "%d bytes allocated %d units total\n", len, count); 00331 return RESULT_SUCCESS; 00332 } 00333 00334 static char show_memory_help[] = 00335 "Usage: show memory allocations [<file>]\n" 00336 " Dumps a list of all segments of allocated memory, optionally\n" 00337 "limited to those from a specific file\n"; 00338 00339 static char show_memory_summary_help[] = 00340 "Usage: show memory summary [<file>]\n" 00341 " Summarizes heap memory allocations by file, or optionally\n" 00342 "by function, if a file is specified\n"; 00343 00344 static struct ast_cli_entry show_memory_allocations_cli = 00345 { { "show", "memory", "allocations", NULL }, 00346 handle_show_memory, "Display outstanding memory allocations", 00347 show_memory_help }; 00348 00349 static struct ast_cli_entry show_memory_summary_cli = 00350 { { "show", "memory", "summary", NULL }, 00351 handle_show_memory_summary, "Summarize outstanding memory allocations", 00352 show_memory_summary_help }; 00353 00354 00355 void __ast_mm_init(void) 00356 { 00357 ast_cli_register(&show_memory_allocations_cli); 00358 ast_cli_register(&show_memory_summary_cli); 00359 mmlog = fopen("/var/log/asterisk/mmlog", "a+"); 00360 if (option_verbose) 00361 ast_verbose("Asterisk Malloc Debugger Started (see /var/log/asterisk/mmlog)\n"); 00362 if (mmlog) { 00363 fprintf(mmlog, "%ld - New session\n", time(NULL)); 00364 fflush(mmlog); 00365 } 00366 } 00367 00368 #endif

Generated on Sat Jun 12 16:40:57 2004 for Asterisk by doxygen 1.3.7