Fri Aug 24 02:22:11 2007

Asterisk developer's documentation


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$")
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_NOTRACKING(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(&reglock);
00121    reg->next = regions[hash];
00122    regions[hash] = reg;
00123    ast_mutex_unlock(&reglock);
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(&reglock);
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(&reglock);
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(&reglock);
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(&reglock);
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(&reglock);
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(&reglock);
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_show_memory_allocations_deprecated = {
00445    { "show", "memory", "allocations", NULL },
00446    handle_show_memory, NULL,
00447    NULL };
00448 
00449 static struct ast_cli_entry cli_show_memory_summary_deprecated = {
00450    { "show", "memory", "summary", NULL },
00451    handle_show_memory_summary, NULL,
00452    NULL };
00453 
00454 static struct ast_cli_entry cli_memory[] = {
00455    { { "memory", "show", "allocations", NULL },
00456    handle_show_memory, "Display outstanding memory allocations",
00457    show_memory_help, NULL, &cli_show_memory_allocations_deprecated },
00458 
00459    { { "memory", "show", "summary", NULL },
00460    handle_show_memory_summary, "Summarize outstanding memory allocations",
00461    show_memory_summary_help, NULL, &cli_show_memory_summary_deprecated },
00462 };
00463 
00464 void __ast_mm_init(void)
00465 {
00466    char filename[PATH_MAX];
00467 
00468    ast_cli_register_multiple(cli_memory, sizeof(cli_memory) / sizeof(struct ast_cli_entry));
00469    
00470    snprintf(filename, sizeof(filename), "%s/mmlog", (char *)ast_config_AST_LOG_DIR);
00471    
00472    if (option_verbose)
00473       ast_verbose("Asterisk Malloc Debugger Started (see %s))\n", filename);
00474    
00475    if ((mmlog = fopen(filename, "a+"))) {
00476       fprintf(mmlog, "%ld - New session\n", time(NULL));
00477       fflush(mmlog);
00478    }
00479 }
00480 
00481 #endif

Generated on Fri Aug 24 02:22:11 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.1