![]() |
Home page |
Mailing list |
Docs
Asterisk developer's documentation :: Codename Pineapple
astmm.c
Go to the documentation of this file.
00001 /* 00002 * Asterisk -- An open source telephony toolkit. 00003 * 00004 * Copyright (C) 1999 - 2006, Digium, Inc. 00005 * 00006 * Mark Spencer <markster@digium.com> 00007 * 00008 * See http://www.asterisk.org for more information about 00009 * the Asterisk project. Please do not directly contact 00010 * any of the maintainers of this project for assistance; 00011 * the project provides a web site, mailing lists and IRC 00012 * channels for your use. 00013 * 00014 * This program is free software, distributed under the terms of 00015 * the GNU General Public License Version 2. See the LICENSE file 00016 * at the top of the source tree. 00017 */ 00018 00019 /*! \file 00020 * 00021 * \brief Memory Management 00022 * 00023 * \author Mark Spencer <markster@digium.com> 00024 */ 00025 00026 #ifdef __AST_DEBUG_MALLOC 00027 00028 #include "asterisk.h" 00029 00030 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 50833 $") 00031 00032 #include <stdio.h> 00033 #include <string.h> 00034 #include <time.h> 00035 00036 #include "asterisk/cli.h" 00037 #include "asterisk/logger.h" 00038 #include "asterisk/options.h" 00039 #include "asterisk/lock.h" 00040 #include "asterisk/strings.h" 00041 #include "asterisk/unaligned.h" 00042 00043 #define SOME_PRIME 563 00044 00045 enum func_type { 00046 FUNC_CALLOC = 1, 00047 FUNC_MALLOC, 00048 FUNC_REALLOC, 00049 FUNC_STRDUP, 00050 FUNC_STRNDUP, 00051 FUNC_VASPRINTF, 00052 FUNC_ASPRINTF 00053 }; 00054 00055 /* Undefine all our macros */ 00056 #undef malloc 00057 #undef calloc 00058 #undef realloc 00059 #undef strdup 00060 #undef strndup 00061 #undef free 00062 #undef vasprintf 00063 #undef asprintf 00064 00065 #define FENCE_MAGIC 0xdeadbeef 00066 00067 static FILE *mmlog; 00068 00069 static struct ast_region { 00070 struct ast_region *next; 00071 char file[40]; 00072 char func[40]; 00073 unsigned int lineno; 00074 enum func_type which; 00075 unsigned int cache; /* region was allocated as part of a cache pool */ 00076 size_t len; 00077 unsigned int fence; 00078 unsigned char data[0]; 00079 } *regions[SOME_PRIME]; 00080 00081 #define HASH(a) \ 00082 (((unsigned long)(a)) % SOME_PRIME) 00083 00084 AST_MUTEX_DEFINE_STATIC(reglock); 00085 AST_MUTEX_DEFINE_STATIC(showmemorylock); 00086 00087 #define astmm_log(...) \ 00088 do { \ 00089 fprintf(stderr, __VA_ARGS__); \ 00090 if (mmlog) { \ 00091 fprintf(mmlog, __VA_ARGS__); \ 00092 fflush(mmlog); \ 00093 } \ 00094 } while (0) 00095 00096 static inline void *__ast_alloc_region(size_t size, const enum func_type which, const char *file, int lineno, const char *func, unsigned int cache) 00097 { 00098 struct ast_region *reg; 00099 void *ptr = NULL; 00100 unsigned int *fence; 00101 int hash; 00102 00103 if (!(reg = malloc(size + sizeof(*reg) + sizeof(*fence)))) { 00104 astmm_log("Memory Allocation Failure - '%d' bytes in function %s " 00105 "at line %d of %s\n", (int) size, func, lineno, file); 00106 } 00107 00108 ast_copy_string(reg->file, file, sizeof(reg->file)); 00109 ast_copy_string(reg->func, func, sizeof(reg->func)); 00110 reg->lineno = lineno; 00111 reg->len = size; 00112 reg->which = which; 00113 reg->cache = cache; 00114 ptr = reg->data; 00115 hash = HASH(ptr); 00116 reg->fence = FENCE_MAGIC; 00117 fence = (ptr + reg->len); 00118 put_unaligned_uint32(fence, FENCE_MAGIC); 00119 00120 ast_mutex_lock(®lock); 00121 reg->next = regions[hash]; 00122 regions[hash] = reg; 00123 ast_mutex_unlock(®lock); 00124 00125 return ptr; 00126 } 00127 00128 static inline size_t __ast_sizeof_region(void *ptr) 00129 { 00130 int hash = HASH(ptr); 00131 struct ast_region *reg; 00132 size_t len = 0; 00133 00134 ast_mutex_lock(®lock); 00135 for (reg = regions[hash]; reg; reg = reg->next) { 00136 if (reg->data == ptr) { 00137 len = reg->len; 00138 break; 00139 } 00140 } 00141 ast_mutex_unlock(®lock); 00142 00143 return len; 00144 } 00145 00146 static void __ast_free_region(void *ptr, const char *file, int lineno, const char *func) 00147 { 00148 int hash = HASH(ptr); 00149 struct ast_region *reg, *prev = NULL; 00150 unsigned int *fence; 00151 00152 ast_mutex_lock(®lock); 00153 for (reg = regions[hash]; reg; reg = reg->next) { 00154 if (reg->data == ptr) { 00155 if (prev) 00156 prev->next = reg->next; 00157 else 00158 regions[hash] = reg->next; 00159 break; 00160 } 00161 prev = reg; 00162 } 00163 ast_mutex_unlock(®lock); 00164 00165 if (reg) { 00166 fence = (unsigned int *)(reg->data + reg->len); 00167 if (reg->fence != FENCE_MAGIC) { 00168 astmm_log("WARNING: Low fence violation at %p, in %s of %s, " 00169 "line %d\n", reg->data, reg->func, reg->file, reg->lineno); 00170 } 00171 if (get_unaligned_uint32(fence) != FENCE_MAGIC) { 00172 astmm_log("WARNING: High fence violation at %p, in %s of %s, " 00173 "line %d\n", reg->data, reg->func, reg->file, reg->lineno); 00174 } 00175 free(reg); 00176 } else { 00177 astmm_log("WARNING: Freeing unused memory at %p, in %s of %s, line %d\n", 00178 ptr, func, file, lineno); 00179 } 00180 } 00181 00182 void *__ast_calloc(size_t nmemb, size_t size, const char *file, int lineno, const char *func) 00183 { 00184 void *ptr; 00185 00186 if ((ptr = __ast_alloc_region(size * nmemb, FUNC_CALLOC, file, lineno, func, 0))) 00187 memset(ptr, 0, size * nmemb); 00188 00189 return ptr; 00190 } 00191 00192 void *__ast_calloc_cache(size_t nmemb, size_t size, const char *file, int lineno, const char *func) 00193 { 00194 void *ptr; 00195 00196 if ((ptr = __ast_alloc_region(size * nmemb, FUNC_CALLOC, file, lineno, func, 1))) 00197 memset(ptr, 0, size * nmemb); 00198 00199 return ptr; 00200 } 00201 00202 void *__ast_malloc(size_t size, const char *file, int lineno, const char *func) 00203 { 00204 return __ast_alloc_region(size, FUNC_MALLOC, file, lineno, func, 0); 00205 } 00206 00207 void __ast_free(void *ptr, const char *file, int lineno, const char *func) 00208 { 00209 __ast_free_region(ptr, file, lineno, func); 00210 } 00211 00212 void *__ast_realloc(void *ptr, size_t size, const char *file, int lineno, const char *func) 00213 { 00214 void *tmp; 00215 size_t len = 0; 00216 00217 if (ptr && !(len = __ast_sizeof_region(ptr))) { 00218 astmm_log("WARNING: Realloc of unalloced memory at %p, in %s of %s, " 00219 "line %d\n", ptr, func, file, lineno); 00220 return NULL; 00221 } 00222 00223 if (!(tmp = __ast_alloc_region(size, FUNC_REALLOC, file, lineno, func, 0))) 00224 return NULL; 00225 00226 if (len > size) 00227 len = size; 00228 if (ptr) { 00229 memcpy(tmp, ptr, len); 00230 __ast_free_region(ptr, file, lineno, func); 00231 } 00232 00233 return tmp; 00234 } 00235 00236 char *__ast_strdup(const char *s, const char *file, int lineno, const char *func) 00237 { 00238 size_t len; 00239 void *ptr; 00240 00241 if (!s) 00242 return NULL; 00243 00244 len = strlen(s) + 1; 00245 if ((ptr = __ast_alloc_region(len, FUNC_STRDUP, file, lineno, func, 0))) 00246 strcpy(ptr, s); 00247 00248 return ptr; 00249 } 00250 00251 char *__ast_strndup(const char *s, size_t n, const char *file, int lineno, const char *func) 00252 { 00253 size_t len; 00254 void *ptr; 00255 00256 if (!s) 00257 return NULL; 00258 00259 len = strlen(s) + 1; 00260 if (len > n) 00261 len = n; 00262 if ((ptr = __ast_alloc_region(len, FUNC_STRNDUP, file, lineno, func, 0))) 00263 strcpy(ptr, s); 00264 00265 return ptr; 00266 } 00267 00268 int __ast_asprintf(const char *file, int lineno, const char *func, char **strp, const char *fmt, ...) 00269 { 00270 int size; 00271 va_list ap, ap2; 00272 char s; 00273 00274 *strp = NULL; 00275 va_start(ap, fmt); 00276 va_copy(ap2, ap); 00277 size = vsnprintf(&s, 1, fmt, ap2); 00278 va_end(ap2); 00279 if (!(*strp = __ast_alloc_region(size + 1, FUNC_ASPRINTF, file, lineno, func, 0))) { 00280 va_end(ap); 00281 return -1; 00282 } 00283 vsnprintf(*strp, size + 1, fmt, ap); 00284 va_end(ap); 00285 00286 return size; 00287 } 00288 00289 int __ast_vasprintf(char **strp, const char *fmt, va_list ap, const char *file, int lineno, const char *func) 00290 { 00291 int size; 00292 va_list ap2; 00293 char s; 00294 00295 *strp = NULL; 00296 va_copy(ap2, ap); 00297 size = vsnprintf(&s, 1, fmt, ap2); 00298 va_end(ap2); 00299 if (!(*strp = __ast_alloc_region(size + 1, FUNC_VASPRINTF, file, lineno, func, 0))) { 00300 va_end(ap); 00301 return -1; 00302 } 00303 vsnprintf(*strp, size + 1, fmt, ap); 00304 00305 return size; 00306 } 00307 00308 static int handle_show_memory(int fd, int argc, char *argv[]) 00309 { 00310 char *fn = NULL; 00311 struct ast_region *reg; 00312 unsigned int x; 00313 unsigned int len = 0; 00314 unsigned int cache_len = 0; 00315 unsigned int count = 0; 00316 unsigned int *fence; 00317 00318 if (argc > 3) 00319 fn = argv[3]; 00320 00321 ast_mutex_lock(&showmemorylock); 00322 for (x = 0; x < SOME_PRIME; x++) { 00323 for (reg = regions[x]; reg; reg = reg->next) { 00324 if (!fn || !strcasecmp(fn, reg->file) || !strcasecmp(fn, "anomolies")) { 00325 fence = (unsigned int *)(reg->data + reg->len); 00326 if (reg->fence != FENCE_MAGIC) { 00327 astmm_log("WARNING: Low fence violation at %p, " 00328 "in %s of %s, line %d\n", reg->data, 00329 reg->func, reg->file, reg->lineno); 00330 } 00331 if (get_unaligned_uint32(fence) != FENCE_MAGIC) { 00332 astmm_log("WARNING: High fence violation at %p, in %s of %s, " 00333 "line %d\n", reg->data, reg->func, reg->file, reg->lineno); 00334 } 00335 } 00336 if (!fn || !strcasecmp(fn, reg->file)) { 00337 ast_cli(fd, "%10d bytes allocated%s in %20s at line %5d of %s\n", 00338 (int) reg->len, reg->cache ? " (cache)" : "", 00339 reg->func, reg->lineno, reg->file); 00340 len += reg->len; 00341 if (reg->cache) 00342 cache_len += reg->len; 00343 count++; 00344 } 00345 } 00346 } 00347 ast_mutex_unlock(&showmemorylock); 00348 00349 if (cache_len) 00350 ast_cli(fd, "%d bytes allocated (%d in caches) in %d allocations\n", len, cache_len, count); 00351 else 00352 ast_cli(fd, "%d bytes allocated in %d allocations\n", len, count); 00353 00354 return RESULT_SUCCESS; 00355 } 00356 00357 static int handle_show_memory_summary(int fd, int argc, char *argv[]) 00358 { 00359 char *fn = NULL; 00360 int x; 00361 struct ast_region *reg; 00362 unsigned int len = 0; 00363 unsigned int cache_len = 0; 00364 int count = 0; 00365 struct file_summary { 00366 char fn[80]; 00367 int len; 00368 int cache_len; 00369 int count; 00370 struct file_summary *next; 00371 } *list = NULL, *cur; 00372 00373 if (argc > 3) 00374 fn = argv[3]; 00375 00376 ast_mutex_lock(®lock); 00377 for (x = 0; x < SOME_PRIME; x++) { 00378 for (reg = regions[x]; reg; reg = reg->next) { 00379 if (fn && strcasecmp(fn, reg->file)) 00380 continue; 00381 00382 for (cur = list; cur; cur = cur->next) { 00383 if ((!fn && !strcmp(cur->fn, reg->file)) || (fn && !strcmp(cur->fn, reg->func))) 00384 break; 00385 } 00386 if (!cur) { 00387 cur = alloca(sizeof(*cur)); 00388 memset(cur, 0, sizeof(*cur)); 00389 ast_copy_string(cur->fn, fn ? reg->func : reg->file, sizeof(cur->fn)); 00390 cur->next = list; 00391 list = cur; 00392 } 00393 00394 cur->len += reg->len; 00395 if (reg->cache) 00396 cur->cache_len += reg->len; 00397 cur->count++; 00398 } 00399 } 00400 ast_mutex_unlock(®lock); 00401 00402 /* Dump the whole list */ 00403 for (cur = list; cur; cur = cur->next) { 00404 len += cur->len; 00405 cache_len += cur->cache_len; 00406 count += cur->count; 00407 if (cur->cache_len) { 00408 if (fn) { 00409 ast_cli(fd, "%10d bytes (%10d cache) in %d allocations in function '%s' of '%s'\n", 00410 cur->len, cur->cache_len, cur->count, cur->fn, fn); 00411 } else { 00412 ast_cli(fd, "%10d bytes (%10d cache) in %d allocations in file '%s'\n", 00413 cur->len, cur->cache_len, cur->count, cur->fn); 00414 } 00415 } else { 00416 if (fn) { 00417 ast_cli(fd, "%10d bytes in %d allocations in function '%s' of '%s'\n", 00418 cur->len, cur->count, cur->fn, fn); 00419 } else { 00420 ast_cli(fd, "%10d bytes in %d allocations in file '%s'\n", 00421 cur->len, cur->count, cur->fn); 00422 } 00423 } 00424 } 00425 00426 if (cache_len) 00427 ast_cli(fd, "%d bytes allocated (%d in caches) in %d allocations\n", len, cache_len, count); 00428 else 00429 ast_cli(fd, "%d bytes allocated in %d allocations\n", len, count); 00430 00431 return RESULT_SUCCESS; 00432 } 00433 00434 static char show_memory_help[] = 00435 "Usage: memory show allocations [<file>]\n" 00436 " Dumps a list of all segments of allocated memory, optionally\n" 00437 "limited to those from a specific file\n"; 00438 00439 static char show_memory_summary_help[] = 00440 "Usage: memory show summary [<file>]\n" 00441 " Summarizes heap memory allocations by file, or optionally\n" 00442 "by function, if a file is specified\n"; 00443 00444 static struct ast_cli_entry cli_memory[] = { 00445 { { "memory", "show", "allocations", NULL }, 00446 handle_show_memory, "Display outstanding memory allocations", 00447 show_memory_help }, 00448 00449 { { "memory", "show", "summary", NULL }, 00450 handle_show_memory_summary, "Summarize outstanding memory allocations", 00451 show_memory_summary_help }, 00452 }; 00453 00454 void __ast_mm_init(void) 00455 { 00456 char filename[PATH_MAX]; 00457 00458 ast_cli_register_multiple(cli_memory, sizeof(cli_memory) / sizeof(struct ast_cli_entry)); 00459 00460 snprintf(filename, sizeof(filename), "%s/mmlog", (char *)ast_config_AST_LOG_DIR); 00461 00462 if (option_verbose) 00463 ast_verbose("Asterisk Malloc Debugger Started (see %s))\n", filename); 00464 00465 if ((mmlog = fopen(filename, "a+"))) { 00466 fprintf(mmlog, "%ld - New session\n", time(NULL)); 00467 fflush(mmlog); 00468 } 00469 } 00470 00471 #endif