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

Generated on Sun Apr 18 23:33:48 2004 for Asterisk by doxygen 1.3.6-20040222