Asterisk.org: Developer Documentation (28 Oct 2009)

Wed Oct 28 15:47:49 2009

## Asterisk developer's documentation

- Main Page
- Related Pages
- Modules
- Data Structures
- Files
- Directories

# astmm.c

Go to the documentation of this file.

    00001 /*
    00002  * Asterisk -- An open source telephony toolkit.
    00003  *
    00004  * Copyright (C) 1999 - 2005, 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  */
    00024
    00025 #ifdef __AST_DEBUG_MALLOC
    00026
    00027 #include <stdio.h>
    00028 #include <string.h>
    00029 #include <time.h>
    00030
    00031 #include "asterisk.h"
    00032
    00033 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 15743 $")
    00034
    00035 #include "asterisk/cli.h"
    00036 #include "asterisk/logger.h"
    00037 #include "asterisk/options.h"
    00038 #include "asterisk/lock.h"
    00039 #include "asterisk/strings.h"
    00040 #include "asterisk/unaligned.h"
    00041
    00042 #define SOME_PRIME 563
    00043
    00044 #define FUNC_CALLOC  1
    00045 #define FUNC_MALLOC  2
    00046 #define FUNC_REALLOC 3
    00047 #define FUNC_STRDUP  4
    00048 #define FUNC_STRNDUP 5
    00049 #define FUNC_VASPRINTF  6
    00050
    00051 /* Undefine all our macros */
    00052 #undef malloc
    00053 #undef calloc
    00054 #undef realloc
    00055 #undef strdup
    00056 #undef strndup
    00057 #undef free
    00058 #undef vasprintf
    00059
    00060 #define FENCE_MAGIC 0xdeadbeef
    00061
    00062 static FILE *mmlog;
    00063
    00064 static struct ast_region {
    00065    struct ast_region *next;
    00066    char file[40];
    00067    char func[40];
    00068    int lineno;
    00069    int which;
    00070    size_t len;
    00071    unsigned int fence;
    00072    unsigned char data[0];
    00073 } *regions[SOME_PRIME];
    00074
    00075 #define HASH(a) \
    00076    (((unsigned long)(a)) % SOME_PRIME)
    00077
    00078 AST_MUTEX_DEFINE_STATIC(reglock);
    00079 AST_MUTEX_DEFINE_STATIC(showmemorylock);
    00080
    00081 static inline void *__ast_alloc_region(size_t size, int which, const char *file, int lineno, const char *func)
    00082 {
    00083    struct ast_region *reg;
    00084    void *ptr = NULL;
    00085    unsigned int *fence;
    00086    int hash;
    00087    reg = malloc(size + sizeof(struct ast_region) + sizeof(unsigned int));
    00088    ast_mutex_lock(&reglock);
    00089    if (reg) {
    00090       ast_copy_string(reg->file, file, sizeof(reg->file));
    00091       reg->file[sizeof(reg->file) - 1] = '\0';
    00092       ast_copy_string(reg->func, func, sizeof(reg->func));
    00093       reg->func[sizeof(reg->func) - 1] = '\0';
    00094       reg->lineno = lineno;
    00095       reg->len = size;
    00096       reg->which = which;
    00097       ptr = reg->data;
    00098       hash = HASH(ptr);
    00099       reg->next = regions[hash];
    00100       regions[hash] = reg;
    00101       reg->fence = FENCE_MAGIC;
    00102       fence = (ptr + reg->len);
    00103       put_unaligned_uint32(fence, FENCE_MAGIC);
    00104    }
    00105    ast_mutex_unlock(&reglock);
    00106    if (!reg) {
    00107       fprintf(stderr, "Out of memory :(\n");
    00108       if (mmlog) {
    00109          fprintf(mmlog, "%ld - Out of memory\n", time(NULL));
    00110          fflush(mmlog);
    00111       }
    00112    }
    00113    return ptr;
    00114 }
    00115
    00116 static inline size_t __ast_sizeof_region(void *ptr)
    00117 {
    00118    int hash = HASH(ptr);
    00119    struct ast_region *reg;
    00120    size_t len = 0;
    00121
    00122    ast_mutex_lock(&reglock);
    00123    reg = regions[hash];
    00124    while (reg) {
    00125       if (reg->data == ptr) {
    00126          len = reg->len;
    00127          break;
    00128       }
    00129       reg = reg->next;
    00130    }
    00131    ast_mutex_unlock(&reglock);
    00132    return len;
    00133 }
    00134
    00135 static void __ast_free_region(void *ptr, const char *file, int lineno, const char *func)
    00136 {
    00137    int hash = HASH(ptr);
    00138    struct ast_region *reg, *prev = NULL;
    00139    unsigned int *fence;
    00140
    00141    ast_mutex_lock(&reglock);
    00142    reg = regions[hash];
    00143    while (reg) {
    00144       if (reg->data == ptr) {
    00145          if (prev) {
    00146             prev->next = reg->next;
    00147          } else {
    00148             regions[hash] = reg->next;
    00149          }
    00150          break;
    00151       }
    00152       prev = reg;
    00153       reg = reg->next;
    00154    }
    00155    ast_mutex_unlock(&reglock);
    00156    if (reg) {
    00157       fence = (unsigned int *)(reg->data + reg->len);
    00158       if (reg->fence != FENCE_MAGIC) {
    00159          fprintf(stderr, "WARNING: Low fence violation at %p, in %s of %s, line %d\n", reg->data, reg->func, reg->file, reg->lineno);
    00160          if (mmlog) {
    00161             fprintf(mmlog, "%ld - WARNING: Low fence violation at %p, in %s of %s, line %d\n", time(NULL), reg->data, reg->func, reg->file, reg->lineno);
    00162             fflush(mmlog);
    00163          }
    00164       }
    00165       if (get_unaligned_uint32(fence) != FENCE_MAGIC) {
    00166          fprintf(stderr, "WARNING: High fence violation at %p, in %s of %s, line %d\n", reg->data, reg->func, reg->file, reg->lineno);
    00167          if (mmlog) {
    00168             fprintf(mmlog, "%ld - WARNING: High fence violation at %p, in %s of %s, line %d\n", time(NULL), reg->data, reg->func, reg->file, reg->lineno);
    00169             fflush(mmlog);
    00170          }
    00171       }
    00172       free(reg);
    00173    } else {
    00174       fprintf(stderr, "WARNING: Freeing unused memory at %p, in %s of %s, line %d\n",  ptr, func, file, lineno);
    00175       if (mmlog) {
    00176          fprintf(mmlog, "%ld - WARNING: Freeing unused memory at %p, in %s of %s, line %d\n", time(NULL), ptr, func, file, lineno);
    00177          fflush(mmlog);
    00178       }
    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    ptr = __ast_alloc_region(size * nmemb, FUNC_CALLOC, file, lineno, func);
    00186    if (ptr)
    00187       memset(ptr, 0, size * nmemb);
    00188    return ptr;
    00189 }
    00190
    00191 void *__ast_malloc(size_t size, const char *file, int lineno, const char *func)
    00192 {
    00193    return __ast_alloc_region(size, FUNC_MALLOC, file, lineno, func);
    00194 }
    00195
    00196 void __ast_free(void *ptr, const char *file, int lineno, const char *func)
    00197 {
    00198    __ast_free_region(ptr, file, lineno, func);
    00199 }
    00200
    00201 void *__ast_realloc(void *ptr, size_t size, const char *file, int lineno, const char *func)
    00202 {
    00203    void *tmp;
    00204    size_t len = 0;
    00205    if (ptr) {
    00206       len = __ast_sizeof_region(ptr);
    00207       if (!len) {
    00208          fprintf(stderr, "WARNING: Realloc of unalloced memory at %p, in %s of %s, line %d\n", ptr, func, file, lineno);
    00209          if (mmlog) {
    00210             fprintf(mmlog, "%ld - WARNING: Realloc of unalloced memory at %p, in %s of %s, line %d\n", time(NULL), ptr, func, file, lineno);
    00211             fflush(mmlog);
    00212          }
    00213          return NULL;
    00214       }
    00215    }
    00216    tmp = __ast_alloc_region(size, FUNC_REALLOC, file, lineno, func);
    00217    if (tmp) {
    00218       if (len > size)
    00219          len = size;
    00220       if (ptr) {
    00221          memcpy(tmp, ptr, len);
    00222          __ast_free_region(ptr, file, lineno, func);
    00223       }
    00224    }
    00225    return tmp;
    00226 }
    00227
    00228 char *__ast_strdup(const char *s, const char *file, int lineno, const char *func)
    00229 {
    00230    size_t len;
    00231    void *ptr;
    00232    if (!s)
    00233       return NULL;
    00234    len = strlen(s) + 1;
    00235    ptr = __ast_alloc_region(len, FUNC_STRDUP, file, lineno, func);
    00236    if (ptr)
    00237       strcpy(ptr, s);
    00238    return ptr;
    00239 }
    00240
    00241 char *__ast_strndup(const char *s, size_t n, const char *file, int lineno, const char *func)
    00242 {
    00243    size_t len;
    00244    void *ptr;
    00245    if (!s)
    00246       return NULL;
    00247    len = strlen(s) + 1;
    00248    if (len > n)
    00249       len = n;
    00250    ptr = __ast_alloc_region(len, FUNC_STRNDUP, file, lineno, func);
    00251    if (ptr)
    00252       strcpy(ptr, s);
    00253    return ptr;
    00254 }
    00255
    00256 int __ast_vasprintf(char **strp, const char *fmt, va_list ap, const char *file, int lineno, const char *func)
    00257 {
    00258    int size;
    00259    va_list ap2;
    00260    char s;
    00261
    00262    *strp = NULL;
    00263    va_copy(ap2, ap);
    00264    size = vsnprintf(&s, 1, fmt, ap2);
    00265    va_end(ap2);
    00266    *strp = __ast_alloc_region(size + 1, FUNC_VASPRINTF, file, lineno, func);
    00267    if (!*strp)
    00268       return -1;
    00269    vsnprintf(*strp, size + 1, fmt, ap);
    00270
    00271    return size;
    00272 }
    00273
    00274 static int handle_show_memory(int fd, int argc, char *argv[])
    00275 {
    00276    char *fn = NULL;
    00277    int x;
    00278    struct ast_region *reg;
    00279    unsigned int len = 0;
    00280    int count = 0;
    00281    unsigned int *fence;
    00282    if (argc > 3)
    00283       fn = argv[3];
    00284
    00285    /* try to lock applications list ... */
    00286    ast_mutex_lock(&showmemorylock);
    00287
    00288    for (x = 0; x < SOME_PRIME; x++) {
    00289       reg = regions[x];
    00290       while (reg) {
    00291          if (!fn || !strcasecmp(fn, reg->file) || !strcasecmp(fn, "anomolies")) {
    00292             fence = (unsigned int *)(reg->data + reg->len);
    00293             if (reg->fence != FENCE_MAGIC) {
    00294                fprintf(stderr, "WARNING: Low fence violation at %p, in %s of %s, line %d\n", reg->data, reg->func, reg->file, reg->lineno);
    00295                if (mmlog) {
    00296                   fprintf(mmlog, "%ld - WARNING: Low fence violation at %p, in %s of %s, line %d\n", time(NULL), reg->data, reg->func, reg-> file, reg->lineno);
    00297                   fflush(mmlog);
    00298                }
    00299             }
    00300             if (get_unaligned_uint32(fence) != FENCE_MAGIC) {
    00301                fprintf(stderr, "WARNING: High fence violation at %p, in %s of %s, line %d\n", reg->data, reg->func, reg->file, reg->lineno);
    00302                if (mmlog) {
    00303                   fprintf(mmlog, "%ld - WARNING: High fence violation at %p, in %s of %s, line %d\n", time(NULL), reg->data, reg->func, reg->file, reg->lineno);
    00304                   fflush(mmlog);
    00305                }
    00306             }
    00307          }
    00308          if (!fn || !strcasecmp(fn, reg->file)) {
    00309             ast_cli(fd, "%10d bytes allocated in %20s at line %5d of %s\n", (int) reg->len, reg->func, reg->lineno, reg->file);
    00310             len += reg->len;
    00311             count++;
    00312          }
    00313          reg = reg->next;
    00314       }
    00315    }
    00316    ast_cli(fd, "%d bytes allocated %d units total\n", len, count);
    00317    ast_mutex_unlock(&showmemorylock);
    00318    return RESULT_SUCCESS;
    00319 }
    00320
    00321 struct file_summary {
    00322    char fn[80];
    00323    int len;
    00324    int count;
    00325    struct file_summary *next;
    00326 };
    00327
    00328 static int handle_show_memory_summary(int fd, int argc, char *argv[])
    00329 {
    00330    char *fn = NULL;
    00331    int x;
    00332    struct ast_region *reg;
    00333    unsigned int len = 0;
    00334    int count = 0;
    00335    struct file_summary *list = NULL, *cur;
    00336
    00337    if (argc > 3)
    00338       fn = argv[3];
    00339
    00340    /* try to lock applications list ... */
    00341    ast_mutex_lock(&reglock);
    00342
    00343    for (x = 0; x < SOME_PRIME; x++) {
    00344       reg = regions[x];
    00345       while (reg) {
    00346          if (!fn || !strcasecmp(fn, reg->file)) {
    00347             cur = list;
    00348             while (cur) {
    00349                if ((!fn && !strcmp(cur->fn, reg->file)) || (fn && !strcmp(cur->fn, reg->func)))
    00350                   break;
    00351                cur = cur->next;
    00352             }
    00353             if (!cur) {
    00354                cur = alloca(sizeof(struct file_summary));
    00355                memset(cur, 0, sizeof(struct file_summary));
    00356                ast_copy_string(cur->fn, fn ? reg->func : reg->file, sizeof(cur->fn));
    00357                cur->next = list;
    00358                list = cur;
    00359             }
    00360             cur->len += reg->len;
    00361             cur->count++;
    00362          }
    00363          reg = reg->next;
    00364       }
    00365    }
    00366    ast_mutex_unlock(&reglock);
    00367
    00368    /* Dump the whole list */
    00369    while (list) {
    00370       cur = list;
    00371       len += list->len;
    00372       count += list->count;
    00373       if (fn) {
    00374          ast_cli(fd, "%10d bytes in %5d allocations in function '%s' of '%s'\n", list->len, list->count, list->fn, fn);
    00375       } else {
    00376          ast_cli(fd, "%10d bytes in %5d allocations in file '%s'\n", list->len, list->count, list->fn);
    00377       }
    00378       list = list->next;
    00379 #if 0
    00380       free(cur);
    00381 #endif
    00382    }
    00383    ast_cli(fd, "%d bytes allocated %d units total\n", len, count);
    00384    return RESULT_SUCCESS;
    00385 }
    00386
    00387 static char show_memory_help[] =
    00388 "Usage: show memory allocations [<file>]\n"
    00389 "       Dumps a list of all segments of allocated memory, optionally\n"
    00390 "limited to those from a specific file\n";
    00391
    00392 static char show_memory_summary_help[] =
    00393 "Usage: show memory summary [<file>]\n"
    00394 "       Summarizes heap memory allocations by file, or optionally\n"
    00395 "by function, if a file is specified\n";
    00396
    00397 static struct ast_cli_entry show_memory_allocations_cli =
    00398    { { "show", "memory", "allocations", NULL },
    00399    handle_show_memory, "Display outstanding memory allocations",
    00400    show_memory_help };
    00401
    00402 static struct ast_cli_entry show_memory_summary_cli =
    00403    { { "show", "memory", "summary", NULL },
    00404    handle_show_memory_summary, "Summarize outstanding memory allocations",
    00405    show_memory_summary_help };
    00406
    00407 void __ast_mm_init(void)
    00408 {
    00409    char filename[80] = "";
    00410    ast_cli_register(&show_memory_allocations_cli);
    00411    ast_cli_register(&show_memory_summary_cli);
    00412
    00413    snprintf(filename, sizeof(filename), "%s/mmlog", (char *)ast_config_AST_LOG_DIR);
    00414    mmlog = fopen(filename, "a+");
    00415    if (option_verbose)
    00416       ast_verbose("Asterisk Malloc Debugger Started (see %s))\n", filename);
    00417    if (mmlog) {
    00418       fprintf(mmlog, "%ld - New session\n", time(NULL));
    00419       fflush(mmlog);
    00420    }
    00421 }
    00422
    00423 #endif