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 <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 Fri Sep 24 21:03:46 2004 for Asterisk by doxygen 1.3.8