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

Generated on Fri Oct 31 07:05:05 2003 for Asterisk by doxygen 1.3.4