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

Generated on Thu Nov 29 22:50:22 2007 for Asterisk by  doxygen 1.4.2