Memory Management. More...
#include "asterisk.h"
#include "asterisk/paths.h"
#include <stddef.h>
#include <time.h>
#include "asterisk/cli.h"
#include "asterisk/lock.h"
#include "asterisk/strings.h"
#include "asterisk/unaligned.h"
Go to the source code of this file.
Data Structures | |
struct | ast_freed_regions |
struct | ast_region |
struct | region_list |
Defines | |
#define | astmm_log(...) |
#define | FENCE_MAGIC 0xfeedbabe |
#define | FREED_MAGIC 0xdeaddead |
#define | FREED_MAX_COUNT 1500 |
#define | HASH(a) (((unsigned long)(a)) % ARRAY_LEN(regions)) |
#define | MALLOC_FILLER 0x55 |
#define | MINNOWS_MAX_SIZE 50 |
#define | my_max(a, b) ((a) >= (b) ? (a) : (b)) |
#define | SOME_PRIME 1567 |
Enumerations | |
enum | func_type { FUNC_CALLOC = 1, FUNC_MALLOC, FUNC_REALLOC, FUNC_STRDUP, FUNC_STRNDUP, FUNC_VASPRINTF, FUNC_ASPRINTF } |
enum | summary_opts { SUMMARY_OFF, SUMMARY_BY_LINE = (1 << 0), SUMMARY_BY_FUNC = (1 << 1), SUMMARY_BY_FILE = (1 << 2) } |
Functions | |
static void * | __ast_alloc_region (size_t size, const enum func_type which, const char *file, int lineno, const char *func, unsigned int cache) |
int | __ast_asprintf (const char *file, int lineno, const char *func, char **strp, const char *fmt,...) |
void * | __ast_calloc (size_t nmemb, size_t size, const char *file, int lineno, const char *func) |
void * | __ast_calloc_cache (size_t nmemb, size_t size, const char *file, int lineno, const char *func) |
void | __ast_free (void *ptr, const char *file, int lineno, const char *func) |
static void | __ast_free_region (void *ptr, const char *file, int lineno, const char *func) |
void * | __ast_malloc (size_t size, const char *file, int lineno, const char *func) |
void | __ast_mm_init_phase_1 (void) |
Initialize malloc debug phase 1. | |
void | __ast_mm_init_phase_2 (void) |
Initialize malloc debug phase 2. | |
void * | __ast_realloc (void *ptr, size_t size, const char *file, int lineno, const char *func) |
char * | __ast_strdup (const char *s, const char *file, int lineno, const char *func) |
char * | __ast_strndup (const char *s, size_t n, const char *file, int lineno, const char *func) |
int | __ast_vasprintf (char **strp, const char *fmt, va_list ap, const char *file, int lineno, const char *func) |
void | ast_free_ptr (void *ptr) |
void * | ast_std_calloc (size_t nmemb, size_t size) |
void | ast_std_free (void *ptr) |
void * | ast_std_malloc (size_t size) |
void * | ast_std_realloc (void *ptr, size_t size) |
static void | freed_regions_flush (struct ast_freed_regions *freed) |
static char * | handle_memory_atexit_list (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
static char * | handle_memory_atexit_summary (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
static char * | handle_memory_show_allocations (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
static char * | handle_memory_show_summary (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
static void | mm_atexit_ast (void) |
static int | mm_atexit_cmp (struct ast_region *left, struct ast_region *right) |
static void | mm_atexit_dump (void) |
static void | mm_atexit_final (void) |
static size_t | mm_atexit_hash_list (struct region_list *list) |
static void | mm_atexit_hash_restore (struct region_list *list) |
static void | mm_atexit_list_merge (struct region_list *list, struct region_list *sub1, struct region_list *sub2) |
static void | mm_atexit_list_sort (struct region_list *list, size_t length) |
static void | mm_atexit_list_split (struct region_list *list, struct region_list sub[], size_t num_lists, size_t size, size_t *remaining) |
static void | mm_atexit_regions_list (struct region_list *alloced) |
static void | mm_atexit_regions_summary (struct region_list *alloced) |
static void | my_do_crash (void) |
static void | region_check_fences (struct ast_region *reg) |
static void | region_data_check (struct ast_region *reg) |
static void | region_data_wipe (struct ast_region *reg) |
static struct ast_region * | region_find (void *ptr) |
static void | region_free (struct ast_freed_regions *freed, struct ast_region *reg) |
static struct ast_region * | region_remove (void *ptr) |
static void | regions_check_all_fences (void) |
Variables | |
static int | atexit_list |
static enum summary_opts | atexit_summary |
static struct ast_cli_entry | cli_memory [] |
static struct ast_freed_regions | minnows |
static FILE * | mmlog |
static struct ast_region * | regions [SOME_PRIME] |
static ast_mutex_t | reglock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 0 } |
static struct ast_freed_regions | whales |
Memory Management.
Definition in file astmm.c.
#define astmm_log | ( | ... | ) |
Definition at line 151 of file astmm.c.
Referenced by __ast_alloc_region(), __ast_free_region(), __ast_realloc(), mm_atexit_dump(), mm_atexit_regions_list(), mm_atexit_regions_summary(), region_check_fences(), and region_data_check().
#define FENCE_MAGIC 0xfeedbabe |
Allocated memory high/low fence overwrite check.
Definition at line 73 of file astmm.c.
Referenced by __ast_alloc_region(), and region_check_fences().
#define FREED_MAGIC 0xdeaddead |
Freed memory wipe filler.
Definition at line 74 of file astmm.c.
Referenced by region_data_check(), and region_data_wipe().
#define FREED_MAX_COUNT 1500 |
#define HASH | ( | a | ) | (((unsigned long)(a)) % ARRAY_LEN(regions)) |
Definition at line 145 of file astmm.c.
Referenced by __ast_alloc_region(), mm_atexit_hash_restore(), region_find(), and region_remove().
#define MALLOC_FILLER 0x55 |
Malloced memory filler. Must not be zero.
Definition at line 75 of file astmm.c.
Referenced by __ast_malloc(), and __ast_realloc().
#define MINNOWS_MAX_SIZE 50 |
Maximum size of a minnow block
Definition at line 115 of file astmm.c.
Referenced by __ast_free_region().
#define my_max | ( | a, | |||
b | ) | ((a) >= (b) ? (a) : (b)) |
Referenced by handle_memory_show_summary().
#define SOME_PRIME 1567 |
enum func_type |
FUNC_CALLOC | |
FUNC_MALLOC | |
FUNC_REALLOC | |
FUNC_STRDUP | |
FUNC_STRNDUP | |
FUNC_VASPRINTF | |
FUNC_ASPRINTF |
Definition at line 53 of file astmm.c.
00053 { 00054 FUNC_CALLOC = 1, 00055 FUNC_MALLOC, 00056 FUNC_REALLOC, 00057 FUNC_STRDUP, 00058 FUNC_STRNDUP, 00059 FUNC_VASPRINTF, 00060 FUNC_ASPRINTF 00061 };
enum summary_opts |
SUMMARY_OFF |
No summary at exit. |
SUMMARY_BY_LINE |
Bit set if summary by line at exit. |
SUMMARY_BY_FUNC |
Bit set if summary by function at exit. |
SUMMARY_BY_FILE |
Bit set if summary by file at exit. |
Definition at line 129 of file astmm.c.
00129 { 00130 /*! No summary at exit. */ 00131 SUMMARY_OFF, 00132 /*! Bit set if summary by line at exit. */ 00133 SUMMARY_BY_LINE = (1 << 0), 00134 /*! Bit set if summary by function at exit. */ 00135 SUMMARY_BY_FUNC = (1 << 1), 00136 /*! Bit set if summary by file at exit. */ 00137 SUMMARY_BY_FILE = (1 << 2), 00138 };
static void* __ast_alloc_region | ( | size_t | size, | |
const enum func_type | which, | |||
const char * | file, | |||
int | lineno, | |||
const char * | func, | |||
unsigned int | cache | |||
) | [static] |
Definition at line 203 of file astmm.c.
References ast_copy_string(), AST_LIST_NEXT, ast_mutex_lock, ast_mutex_unlock, astmm_log, ast_region::cache, ast_region::data, FENCE_MAGIC, ast_region::file, ast_region::func, HASH, ast_region::len, ast_region::lineno, malloc, put_unaligned_uint32(), regions, reglock, and ast_region::which.
Referenced by __ast_asprintf(), __ast_calloc(), __ast_calloc_cache(), __ast_malloc(), __ast_realloc(), __ast_strdup(), __ast_strndup(), and __ast_vasprintf().
00204 { 00205 struct ast_region *reg; 00206 unsigned int *fence; 00207 int hash; 00208 00209 if (!(reg = malloc(size + sizeof(*reg) + sizeof(*fence)))) { 00210 astmm_log("Memory Allocation Failure - '%d' bytes at %s %s() line %d\n", 00211 (int) size, file, func, lineno); 00212 return NULL; 00213 } 00214 00215 reg->len = size; 00216 reg->cache = cache; 00217 reg->lineno = lineno; 00218 reg->which = which; 00219 ast_copy_string(reg->file, file, sizeof(reg->file)); 00220 ast_copy_string(reg->func, func, sizeof(reg->func)); 00221 00222 /* 00223 * Init lower fence. 00224 * 00225 * We use the bytes just preceeding reg->data and not reg->fence 00226 * because there is likely to be padding between reg->fence and 00227 * reg->data for reg->data alignment. 00228 */ 00229 fence = (unsigned int *) (reg->data - sizeof(*fence)); 00230 *fence = FENCE_MAGIC; 00231 00232 /* Init higher fence. */ 00233 fence = (unsigned int *) (reg->data + reg->len); 00234 put_unaligned_uint32(fence, FENCE_MAGIC); 00235 00236 hash = HASH(reg->data); 00237 ast_mutex_lock(®lock); 00238 AST_LIST_NEXT(reg, node) = regions[hash]; 00239 regions[hash] = reg; 00240 ast_mutex_unlock(®lock); 00241 00242 return reg->data; 00243 }
int __ast_asprintf | ( | const char * | file, | |
int | lineno, | |||
const char * | func, | |||
char ** | strp, | |||
const char * | fmt, | |||
... | ||||
) |
Definition at line 609 of file astmm.c.
References __ast_alloc_region(), and FUNC_ASPRINTF.
00610 { 00611 int size; 00612 va_list ap, ap2; 00613 char s; 00614 00615 *strp = NULL; 00616 va_start(ap, fmt); 00617 va_copy(ap2, ap); 00618 size = vsnprintf(&s, 1, fmt, ap2); 00619 va_end(ap2); 00620 if (!(*strp = __ast_alloc_region(size + 1, FUNC_ASPRINTF, file, lineno, func, 0))) { 00621 va_end(ap); 00622 return -1; 00623 } 00624 vsnprintf(*strp, size + 1, fmt, ap); 00625 va_end(ap); 00626 00627 return size; 00628 }
void* __ast_calloc | ( | size_t | nmemb, | |
size_t | size, | |||
const char * | file, | |||
int | lineno, | |||
const char * | func | |||
) |
Definition at line 467 of file astmm.c.
References __ast_alloc_region(), and FUNC_CALLOC.
Referenced by __ast_calloc_with_stringfields(), __ast_datastore_alloc(), add_string_pool(), ast_hashtab_create(), ast_hashtab_dup(), ast_hashtab_insert_immediate_bucket(), ast_hashtab_resize(), ast_hashtab_start_traversal(), ast_hashtab_start_write_traversal(), ast_heap_create(), ast_var_assign(), ast_variable_new(), and internal_ao2_alloc().
00468 { 00469 void *ptr; 00470 00471 ptr = __ast_alloc_region(size * nmemb, FUNC_CALLOC, file, lineno, func, 0); 00472 if (ptr) { 00473 memset(ptr, 0, size * nmemb); 00474 } 00475 00476 return ptr; 00477 }
void* __ast_calloc_cache | ( | size_t | nmemb, | |
size_t | size, | |||
const char * | file, | |||
int | lineno, | |||
const char * | func | |||
) |
Definition at line 479 of file astmm.c.
References __ast_alloc_region(), and FUNC_CALLOC.
00480 { 00481 void *ptr; 00482 00483 ptr = __ast_alloc_region(size * nmemb, FUNC_CALLOC, file, lineno, func, 1); 00484 if (ptr) { 00485 memset(ptr, 0, size * nmemb); 00486 } 00487 00488 return ptr; 00489 }
void __ast_free | ( | void * | ptr, | |
const char * | file, | |||
int | lineno, | |||
const char * | func | |||
) |
Definition at line 504 of file astmm.c.
References __ast_free_region().
00505 { 00506 __ast_free_region(ptr, file, lineno, func); 00507 }
static void __ast_free_region | ( | void * | ptr, | |
const char * | file, | |||
int | lineno, | |||
const char * | func | |||
) | [static] |
Definition at line 438 of file astmm.c.
References astmm_log, ast_region::len, minnows, MINNOWS_MAX_SIZE, my_do_crash(), region_check_fences(), region_free(), region_remove(), and whales.
Referenced by __ast_free(), and __ast_realloc().
00439 { 00440 struct ast_region *reg; 00441 00442 if (!ptr) { 00443 return; 00444 } 00445 00446 reg = region_remove(ptr); 00447 if (reg) { 00448 region_check_fences(reg); 00449 00450 if (reg->len <= MINNOWS_MAX_SIZE) { 00451 region_free(&minnows, reg); 00452 } else { 00453 region_free(&whales, reg); 00454 } 00455 } else { 00456 /* 00457 * This memory region is not registered. It could be because of 00458 * a double free or the memory block was not allocated by the 00459 * malloc debug code. 00460 */ 00461 astmm_log("WARNING: Freeing unregistered memory %p by %s %s() line %d\n", 00462 ptr, file, func, lineno); 00463 my_do_crash(); 00464 } 00465 }
void* __ast_malloc | ( | size_t | size, | |
const char * | file, | |||
int | lineno, | |||
const char * | func | |||
) |
Definition at line 491 of file astmm.c.
References __ast_alloc_region(), FUNC_MALLOC, and MALLOC_FILLER.
Referenced by __ast_cc_config_params_init().
00492 { 00493 void *ptr; 00494 00495 ptr = __ast_alloc_region(size, FUNC_MALLOC, file, lineno, func, 0); 00496 if (ptr) { 00497 /* Make sure that the malloced memory is not zero. */ 00498 memset(ptr, MALLOC_FILLER, size); 00499 } 00500 00501 return ptr; 00502 }
void __ast_mm_init_phase_1 | ( | void | ) |
Initialize malloc debug phase 1.
Definition at line 1395 of file astmm.c.
References mm_atexit_final().
Referenced by main().
01396 { 01397 atexit(mm_atexit_final); 01398 }
void __ast_mm_init_phase_2 | ( | void | ) |
Initialize malloc debug phase 2.
Definition at line 1414 of file astmm.c.
References ARRAY_LEN, ast_cli_register_multiple(), ast_config_AST_LOG_DIR, ast_log(), ast_register_atexit(), ast_verb, LOG_ERROR, and mm_atexit_ast().
Referenced by main().
01415 { 01416 char filename[PATH_MAX]; 01417 01418 ast_cli_register_multiple(cli_memory, ARRAY_LEN(cli_memory)); 01419 01420 snprintf(filename, sizeof(filename), "%s/mmlog", ast_config_AST_LOG_DIR); 01421 01422 ast_verb(1, "Asterisk Malloc Debugger Started (see %s))\n", filename); 01423 01424 mmlog = fopen(filename, "a+"); 01425 if (mmlog) { 01426 fprintf(mmlog, "%ld - New session\n", (long) time(NULL)); 01427 fflush(mmlog); 01428 } else { 01429 ast_log(LOG_ERROR, "Could not open malloc debug log file: %s\n", filename); 01430 } 01431 01432 ast_register_atexit(mm_atexit_ast); 01433 }
void* __ast_realloc | ( | void * | ptr, | |
size_t | size, | |||
const char * | file, | |||
int | lineno, | |||
const char * | func | |||
) |
Definition at line 527 of file astmm.c.
References __ast_alloc_region(), __ast_free_region(), ast_mutex_lock, ast_mutex_unlock, astmm_log, FUNC_REALLOC, ast_region::len, MALLOC_FILLER, my_do_crash(), region_find(), and reglock.
Referenced by grow_heap().
00528 { 00529 size_t len; 00530 struct ast_region *found; 00531 void *new_mem; 00532 00533 if (ptr) { 00534 ast_mutex_lock(®lock); 00535 found = region_find(ptr); 00536 if (!found) { 00537 ast_mutex_unlock(®lock); 00538 astmm_log("WARNING: Realloc of unregistered memory %p by %s %s() line %d\n", 00539 ptr, file, func, lineno); 00540 my_do_crash(); 00541 return NULL; 00542 } 00543 len = found->len; 00544 ast_mutex_unlock(®lock); 00545 } else { 00546 found = NULL; 00547 len = 0; 00548 } 00549 00550 if (!size) { 00551 __ast_free_region(ptr, file, lineno, func); 00552 return NULL; 00553 } 00554 00555 new_mem = __ast_alloc_region(size, FUNC_REALLOC, file, lineno, func, 0); 00556 if (new_mem) { 00557 if (found) { 00558 /* Copy the old data to the new malloced memory. */ 00559 if (size <= len) { 00560 memcpy(new_mem, ptr, size); 00561 } else { 00562 memcpy(new_mem, ptr, len); 00563 /* Make sure that the added memory is not zero. */ 00564 memset(new_mem + len, MALLOC_FILLER, size - len); 00565 } 00566 __ast_free_region(ptr, file, lineno, func); 00567 } else { 00568 /* Make sure that the malloced memory is not zero. */ 00569 memset(new_mem, MALLOC_FILLER, size); 00570 } 00571 } 00572 00573 return new_mem; 00574 }
char* __ast_strdup | ( | const char * | s, | |
const char * | file, | |||
int | lineno, | |||
const char * | func | |||
) |
Definition at line 576 of file astmm.c.
References __ast_alloc_region(), and FUNC_STRDUP.
00577 { 00578 size_t len; 00579 void *ptr; 00580 00581 if (!s) 00582 return NULL; 00583 00584 len = strlen(s) + 1; 00585 if ((ptr = __ast_alloc_region(len, FUNC_STRDUP, file, lineno, func, 0))) 00586 strcpy(ptr, s); 00587 00588 return ptr; 00589 }
char* __ast_strndup | ( | const char * | s, | |
size_t | n, | |||
const char * | file, | |||
int | lineno, | |||
const char * | func | |||
) |
Definition at line 591 of file astmm.c.
References __ast_alloc_region(), and FUNC_STRNDUP.
00592 { 00593 size_t len; 00594 char *ptr; 00595 00596 if (!s) { 00597 return NULL; 00598 } 00599 00600 len = strnlen(s, n); 00601 if ((ptr = __ast_alloc_region(len + 1, FUNC_STRNDUP, file, lineno, func, 0))) { 00602 memcpy(ptr, s, len); 00603 ptr[len] = '\0'; 00604 } 00605 00606 return ptr; 00607 }
int __ast_vasprintf | ( | char ** | strp, | |
const char * | fmt, | |||
va_list | ap, | |||
const char * | file, | |||
int | lineno, | |||
const char * | func | |||
) |
Definition at line 630 of file astmm.c.
References __ast_alloc_region(), and FUNC_VASPRINTF.
00631 { 00632 int size; 00633 va_list ap2; 00634 char s; 00635 00636 *strp = NULL; 00637 va_copy(ap2, ap); 00638 size = vsnprintf(&s, 1, fmt, ap2); 00639 va_end(ap2); 00640 if (!(*strp = __ast_alloc_region(size + 1, FUNC_VASPRINTF, file, lineno, func, 0))) { 00641 va_end(ap); 00642 return -1; 00643 } 00644 vsnprintf(*strp, size + 1, fmt, ap); 00645 00646 return size; 00647 }
void ast_free_ptr | ( | void * | ptr | ) |
Definition at line 180 of file astmm.c.
References ast_free.
Referenced by add_extensions(), ast_extension_state(), ast_extension_state_add_destroy(), ast_merge_contexts_and_delete(), handle_cli_dialplan_add_extension(), load_module(), manage_parked_call(), park_call_full(), parkinglot_activate(), pbx_load_config(), pbx_load_users(), register_exten(), register_peer_exten(), sla_build_station(), and sla_build_trunk().
00181 { 00182 ast_free(ptr); 00183 }
void* ast_std_calloc | ( | size_t | nmemb, | |
size_t | size | |||
) |
Definition at line 165 of file astmm.c.
References calloc.
Referenced by ast_bt_get_symbols().
00166 { 00167 return calloc(nmemb, size); 00168 }
void ast_std_free | ( | void * | ptr | ) |
Definition at line 175 of file astmm.c.
References free.
Referenced by ao2_bt(), ast_backtrace(), ast_bt_get_symbols(), and complete_fn().
00176 { 00177 free(ptr); 00178 }
void* ast_std_malloc | ( | size_t | size | ) |
void* ast_std_realloc | ( | void * | ptr, | |
size_t | size | |||
) |
Definition at line 170 of file astmm.c.
References realloc.
Referenced by ast_bt_get_symbols().
00171 { 00172 return realloc(ptr, size); 00173 }
static void freed_regions_flush | ( | struct ast_freed_regions * | freed | ) | [static] |
Definition at line 304 of file astmm.c.
References ARRAY_LEN, ast_mutex_lock, ast_mutex_unlock, free, ast_freed_regions::index, region_data_check(), ast_freed_regions::regions, and reglock.
Referenced by mm_atexit_final().
00305 { 00306 int idx; 00307 struct ast_region *old; 00308 00309 ast_mutex_lock(®lock); 00310 for (idx = 0; idx < ARRAY_LEN(freed->regions); ++idx) { 00311 old = freed->regions[idx]; 00312 freed->regions[idx] = NULL; 00313 if (old) { 00314 region_data_check(old); 00315 free(old); 00316 } 00317 } 00318 freed->index = 0; 00319 ast_mutex_unlock(®lock); 00320 }
static char* handle_memory_atexit_list | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 649 of file astmm.c.
References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_cli_complete(), ast_false(), ast_true(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, ast_cli_args::n, ast_cli_args::pos, ast_cli_entry::usage, and ast_cli_args::word.
00650 { 00651 switch (cmd) { 00652 case CLI_INIT: 00653 e->command = "memory atexit list"; 00654 e->usage = 00655 "Usage: memory atexit list {on|off}\n" 00656 " Enable dumping a list of still allocated memory segments at exit.\n"; 00657 return NULL; 00658 case CLI_GENERATE: 00659 if (a->pos == 3) { 00660 const char * const options[] = { "off", "on", NULL }; 00661 00662 return ast_cli_complete(a->word, options, a->n); 00663 } 00664 return NULL; 00665 } 00666 00667 if (a->argc != 4) { 00668 return CLI_SHOWUSAGE; 00669 } 00670 00671 if (ast_true(a->argv[3])) { 00672 atexit_list = 1; 00673 } else if (ast_false(a->argv[3])) { 00674 atexit_list = 0; 00675 } else { 00676 return CLI_SHOWUSAGE; 00677 } 00678 00679 ast_cli(a->fd, "The atexit list is: %s\n", atexit_list ? "On" : "Off"); 00680 00681 return CLI_SUCCESS; 00682 }
static char* handle_memory_atexit_summary | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 684 of file astmm.c.
References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_cli_complete(), ast_false(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, ast_cli_args::n, ast_cli_args::pos, SUMMARY_BY_FILE, SUMMARY_BY_FUNC, SUMMARY_BY_LINE, SUMMARY_OFF, ast_cli_entry::usage, and ast_cli_args::word.
00685 { 00686 char buf[80]; 00687 00688 switch (cmd) { 00689 case CLI_INIT: 00690 e->command = "memory atexit summary"; 00691 e->usage = 00692 "Usage: memory atexit summary {off|byline|byfunc|byfile}\n" 00693 " Summary of still allocated memory segments at exit options.\n" 00694 " off - Disable at exit summary.\n" 00695 " byline - Enable at exit summary by file line number.\n" 00696 " byfunc - Enable at exit summary by function name.\n" 00697 " byfile - Enable at exit summary by file.\n" 00698 "\n" 00699 " Note: byline, byfunc, and byfile are cumulative enables.\n"; 00700 return NULL; 00701 case CLI_GENERATE: 00702 if (a->pos == 3) { 00703 const char * const options[] = { "off", "byline", "byfunc", "byfile", NULL }; 00704 00705 return ast_cli_complete(a->word, options, a->n); 00706 } 00707 return NULL; 00708 } 00709 00710 if (a->argc != 4) { 00711 return CLI_SHOWUSAGE; 00712 } 00713 00714 if (ast_false(a->argv[3])) { 00715 atexit_summary = SUMMARY_OFF; 00716 } else if (!strcasecmp(a->argv[3], "byline")) { 00717 atexit_summary |= SUMMARY_BY_LINE; 00718 } else if (!strcasecmp(a->argv[3], "byfunc")) { 00719 atexit_summary |= SUMMARY_BY_FUNC; 00720 } else if (!strcasecmp(a->argv[3], "byfile")) { 00721 atexit_summary |= SUMMARY_BY_FILE; 00722 } else { 00723 return CLI_SHOWUSAGE; 00724 } 00725 00726 if (atexit_summary) { 00727 buf[0] = '\0'; 00728 if (atexit_summary & SUMMARY_BY_LINE) { 00729 strcat(buf, "byline"); 00730 } 00731 if (atexit_summary & SUMMARY_BY_FUNC) { 00732 if (buf[0]) { 00733 strcat(buf, " | "); 00734 } 00735 strcat(buf, "byfunc"); 00736 } 00737 if (atexit_summary & SUMMARY_BY_FILE) { 00738 if (buf[0]) { 00739 strcat(buf, " | "); 00740 } 00741 strcat(buf, "byfile"); 00742 } 00743 } else { 00744 strcpy(buf, "Off"); 00745 } 00746 ast_cli(a->fd, "The atexit summary is: %s\n", buf); 00747 00748 return CLI_SUCCESS; 00749 }
static char* handle_memory_show_allocations | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 751 of file astmm.c.
References ast_cli_args::argc, ast_cli_args::argv, ARRAY_LEN, ast_cli(), AST_LIST_NEXT, ast_mutex_lock, ast_mutex_unlock, ast_region::cache, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, ast_region::file, ast_region::func, ast_region::len, ast_region::lineno, region_check_fences(), regions, regions_check_all_fences(), reglock, and ast_cli_entry::usage.
00752 { 00753 const char *fn = NULL; 00754 struct ast_region *reg; 00755 unsigned int idx; 00756 unsigned int len = 0; 00757 unsigned int cache_len = 0; 00758 unsigned int count = 0; 00759 00760 switch (cmd) { 00761 case CLI_INIT: 00762 e->command = "memory show allocations"; 00763 e->usage = 00764 "Usage: memory show allocations [<file>|anomalies]\n" 00765 " Dumps a list of segments of allocated memory.\n" 00766 " Defaults to listing all memory allocations.\n" 00767 " <file> - Restricts output to memory allocated by the file.\n" 00768 " anomalies - Only check for fence violations.\n"; 00769 return NULL; 00770 case CLI_GENERATE: 00771 return NULL; 00772 } 00773 00774 if (a->argc == 4) { 00775 fn = a->argv[3]; 00776 } else if (a->argc != 3) { 00777 return CLI_SHOWUSAGE; 00778 } 00779 00780 /* Look for historical misspelled option as well. */ 00781 if (fn && (!strcasecmp(fn, "anomalies") || !strcasecmp(fn, "anomolies"))) { 00782 regions_check_all_fences(); 00783 ast_cli(a->fd, "Anomaly check complete.\n"); 00784 return CLI_SUCCESS; 00785 } 00786 00787 ast_mutex_lock(®lock); 00788 for (idx = 0; idx < ARRAY_LEN(regions); ++idx) { 00789 for (reg = regions[idx]; reg; reg = AST_LIST_NEXT(reg, node)) { 00790 if (fn && strcasecmp(fn, reg->file)) { 00791 continue; 00792 } 00793 00794 region_check_fences(reg); 00795 00796 ast_cli(a->fd, "%10u bytes allocated%s by %20s() line %5u of %s\n", 00797 (unsigned int) reg->len, reg->cache ? " (cache)" : "", 00798 reg->func, reg->lineno, reg->file); 00799 00800 len += reg->len; 00801 if (reg->cache) { 00802 cache_len += reg->len; 00803 } 00804 ++count; 00805 } 00806 } 00807 ast_mutex_unlock(®lock); 00808 00809 if (cache_len) { 00810 ast_cli(a->fd, "%u bytes allocated (%u in caches) in %u allocations\n", 00811 len, cache_len, count); 00812 } else { 00813 ast_cli(a->fd, "%u bytes allocated in %u allocations\n", len, count); 00814 } 00815 00816 return CLI_SUCCESS; 00817 }
static char* handle_memory_show_summary | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 819 of file astmm.c.
References ast_cli_args::argc, ast_cli_args::argv, ARRAY_LEN, ast_alloca, ast_cli(), ast_copy_string(), AST_LIST_NEXT, ast_mutex_lock, ast_mutex_unlock, ast_region::cache, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, ast_region::file, ast_region::func, ast_region::len, ast_region::lineno, my_max, name, ast_region::next, regions, reglock, and ast_cli_entry::usage.
00820 { 00821 #define my_max(a, b) ((a) >= (b) ? (a) : (b)) 00822 00823 const char *fn = NULL; 00824 int idx; 00825 int cmp; 00826 struct ast_region *reg; 00827 unsigned int len = 0; 00828 unsigned int cache_len = 0; 00829 unsigned int count = 0; 00830 struct file_summary { 00831 struct file_summary *next; 00832 unsigned int len; 00833 unsigned int cache_len; 00834 unsigned int count; 00835 unsigned int lineno; 00836 char name[my_max(sizeof(reg->file), sizeof(reg->func))]; 00837 } *list = NULL, *cur, **prev; 00838 00839 switch (cmd) { 00840 case CLI_INIT: 00841 e->command = "memory show summary"; 00842 e->usage = 00843 "Usage: memory show summary [<file>]\n" 00844 " Summarizes heap memory allocations by file, or optionally\n" 00845 " by line, if a file is specified.\n"; 00846 return NULL; 00847 case CLI_GENERATE: 00848 return NULL; 00849 } 00850 00851 if (a->argc == 4) { 00852 fn = a->argv[3]; 00853 } else if (a->argc != 3) { 00854 return CLI_SHOWUSAGE; 00855 } 00856 00857 ast_mutex_lock(®lock); 00858 for (idx = 0; idx < ARRAY_LEN(regions); ++idx) { 00859 for (reg = regions[idx]; reg; reg = AST_LIST_NEXT(reg, node)) { 00860 if (fn) { 00861 if (strcasecmp(fn, reg->file)) { 00862 continue; 00863 } 00864 00865 /* Sort list by func/lineno. Find existing or place to insert. */ 00866 for (prev = &list; (cur = *prev); prev = &cur->next) { 00867 cmp = strcmp(cur->name, reg->func); 00868 if (cmp < 0) { 00869 continue; 00870 } 00871 if (cmp > 0) { 00872 /* Insert before current */ 00873 cur = NULL; 00874 break; 00875 } 00876 cmp = cur->lineno - reg->lineno; 00877 if (cmp < 0) { 00878 continue; 00879 } 00880 if (cmp > 0) { 00881 /* Insert before current */ 00882 cur = NULL; 00883 } 00884 break; 00885 } 00886 } else { 00887 /* Sort list by filename. Find existing or place to insert. */ 00888 for (prev = &list; (cur = *prev); prev = &cur->next) { 00889 cmp = strcmp(cur->name, reg->file); 00890 if (cmp < 0) { 00891 continue; 00892 } 00893 if (cmp > 0) { 00894 /* Insert before current */ 00895 cur = NULL; 00896 } 00897 break; 00898 } 00899 } 00900 00901 if (!cur) { 00902 cur = ast_alloca(sizeof(*cur)); 00903 memset(cur, 0, sizeof(*cur)); 00904 cur->lineno = reg->lineno; 00905 ast_copy_string(cur->name, fn ? reg->func : reg->file, sizeof(cur->name)); 00906 00907 cur->next = *prev; 00908 *prev = cur; 00909 } 00910 00911 cur->len += reg->len; 00912 if (reg->cache) { 00913 cur->cache_len += reg->len; 00914 } 00915 ++cur->count; 00916 } 00917 } 00918 ast_mutex_unlock(®lock); 00919 00920 /* Dump the whole list */ 00921 for (cur = list; cur; cur = cur->next) { 00922 len += cur->len; 00923 cache_len += cur->cache_len; 00924 count += cur->count; 00925 if (cur->cache_len) { 00926 if (fn) { 00927 ast_cli(a->fd, "%10u bytes (%10u cache) in %10u allocations by %20s() line %5u of %s\n", 00928 cur->len, cur->cache_len, cur->count, cur->name, cur->lineno, fn); 00929 } else { 00930 ast_cli(a->fd, "%10u bytes (%10u cache) in %10u allocations in file %s\n", 00931 cur->len, cur->cache_len, cur->count, cur->name); 00932 } 00933 } else { 00934 if (fn) { 00935 ast_cli(a->fd, "%10u bytes in %10u allocations by %20s() line %5u of %s\n", 00936 cur->len, cur->count, cur->name, cur->lineno, fn); 00937 } else { 00938 ast_cli(a->fd, "%10u bytes in %10u allocations in file %s\n", 00939 cur->len, cur->count, cur->name); 00940 } 00941 } 00942 } 00943 00944 if (cache_len) { 00945 ast_cli(a->fd, "%u bytes allocated (%u in caches) in %u allocations\n", 00946 len, cache_len, count); 00947 } else { 00948 ast_cli(a->fd, "%u bytes allocated in %u allocations\n", len, count); 00949 } 00950 00951 return CLI_SUCCESS; 00952 }
static void mm_atexit_ast | ( | void | ) | [static] |
Definition at line 1404 of file astmm.c.
References ARRAY_LEN, and ast_cli_unregister_multiple().
Referenced by __ast_mm_init_phase_2().
01405 { 01406 ast_cli_unregister_multiple(cli_memory, ARRAY_LEN(cli_memory)); 01407 }
static int mm_atexit_cmp | ( | struct ast_region * | left, | |
struct ast_region * | right | |||
) | [static] |
Definition at line 1030 of file astmm.c.
References ast_region::data, ast_region::file, ast_region::len, and ast_region::lineno.
Referenced by mm_atexit_list_merge().
01031 { 01032 int cmp; 01033 ptrdiff_t cmp_ptr; 01034 ssize_t cmp_size; 01035 01036 /* Sort by filename. */ 01037 cmp = strcmp(left->file, right->file); 01038 if (cmp) { 01039 return cmp; 01040 } 01041 01042 /* Sort by line number. */ 01043 cmp = left->lineno - right->lineno; 01044 if (cmp) { 01045 return cmp; 01046 } 01047 01048 /* Sort by allocated size. */ 01049 cmp_size = left->len - right->len; 01050 if (cmp_size) { 01051 if (cmp_size < 0) { 01052 return -1; 01053 } 01054 return 1; 01055 } 01056 01057 /* Sort by allocated pointers just because. */ 01058 cmp_ptr = left->data - right->data; 01059 if (cmp_ptr) { 01060 if (cmp_ptr < 0) { 01061 return -1; 01062 } 01063 return 1; 01064 } 01065 01066 return 0; 01067 }
static void mm_atexit_dump | ( | void | ) | [static] |
Definition at line 1322 of file astmm.c.
References AST_LIST_HEAD_NOLOCK_INIT_VALUE, astmm_log, mm_atexit_hash_list(), mm_atexit_hash_restore(), mm_atexit_list_sort(), mm_atexit_regions_list(), and mm_atexit_regions_summary().
Referenced by mm_atexit_final().
01323 { 01324 struct region_list alloced_atexit = AST_LIST_HEAD_NOLOCK_INIT_VALUE; 01325 size_t length; 01326 01327 length = mm_atexit_hash_list(&alloced_atexit); 01328 if (!length) { 01329 /* Wow! This is amazing! */ 01330 astmm_log("Exiting with all memory freed.\n"); 01331 return; 01332 } 01333 01334 mm_atexit_list_sort(&alloced_atexit, length); 01335 01336 astmm_log("Exiting with the following memory not freed:\n"); 01337 if (atexit_list) { 01338 mm_atexit_regions_list(&alloced_atexit); 01339 } 01340 if (atexit_summary) { 01341 mm_atexit_regions_summary(&alloced_atexit); 01342 } 01343 01344 /* 01345 * Put the alloced list back into regions[]. 01346 * 01347 * We have do do this because we can get called before all other 01348 * threads have terminated. 01349 */ 01350 mm_atexit_hash_restore(&alloced_atexit); 01351 }
static void mm_atexit_final | ( | void | ) | [static] |
Definition at line 1357 of file astmm.c.
References ast_mutex_lock, ast_mutex_unlock, freed_regions_flush(), minnows, mm_atexit_dump(), regions_check_all_fences(), reglock, and whales.
Referenced by __ast_mm_init_phase_1().
01358 { 01359 FILE *log; 01360 01361 /* Only wait if we want atexit allocation dumps. */ 01362 if (atexit_list || atexit_summary) { 01363 fprintf(stderr, "Waiting 10 seconds to let other threads die.\n"); 01364 sleep(10); 01365 } 01366 01367 regions_check_all_fences(); 01368 01369 /* Flush all delayed memory free circular arrays. */ 01370 freed_regions_flush(&whales); 01371 freed_regions_flush(&minnows); 01372 01373 /* Peform atexit allocation dumps. */ 01374 if (atexit_list || atexit_summary) { 01375 ast_mutex_lock(®lock); 01376 mm_atexit_dump(); 01377 ast_mutex_unlock(®lock); 01378 } 01379 01380 /* Close the log file. */ 01381 log = mmlog; 01382 mmlog = NULL; 01383 if (log) { 01384 fclose(log); 01385 } 01386 }
static size_t mm_atexit_hash_list | ( | struct region_list * | list | ) | [static] |
Definition at line 979 of file astmm.c.
References ARRAY_LEN, AST_LIST_INSERT_HEAD, AST_LIST_NEXT, and regions.
Referenced by mm_atexit_dump().
00980 { 00981 struct ast_region *reg; 00982 size_t total_length; 00983 int idx; 00984 00985 total_length = 0; 00986 for (idx = 0; idx < ARRAY_LEN(regions); ++idx) { 00987 while ((reg = regions[idx])) { 00988 regions[idx] = AST_LIST_NEXT(reg, node); 00989 AST_LIST_NEXT(reg, node) = NULL; 00990 AST_LIST_INSERT_HEAD(list, reg, node); 00991 ++total_length; 00992 } 00993 } 00994 return total_length; 00995 }
static void mm_atexit_hash_restore | ( | struct region_list * | list | ) | [static] |
Definition at line 1007 of file astmm.c.
References AST_LIST_NEXT, AST_LIST_REMOVE_HEAD, ast_region::data, HASH, and regions.
Referenced by mm_atexit_dump().
01008 { 01009 struct ast_region *reg; 01010 int hash; 01011 01012 while ((reg = AST_LIST_REMOVE_HEAD(list, node))) { 01013 hash = HASH(reg->data); 01014 AST_LIST_NEXT(reg, node) = regions[hash]; 01015 regions[hash] = reg; 01016 } 01017 }
static void mm_atexit_list_merge | ( | struct region_list * | list, | |
struct region_list * | sub1, | |||
struct region_list * | sub2 | |||
) | [static] |
Definition at line 1079 of file astmm.c.
References AST_LIST_APPEND_LIST, AST_LIST_EMPTY, AST_LIST_FIRST, AST_LIST_INSERT_TAIL, AST_LIST_REMOVE_HEAD, and mm_atexit_cmp().
Referenced by mm_atexit_list_sort().
01080 { 01081 struct ast_region *reg; 01082 01083 for (;;) { 01084 if (AST_LIST_EMPTY(sub1)) { 01085 /* The remaining sublist goes onto the list. */ 01086 AST_LIST_APPEND_LIST(list, sub2, node); 01087 break; 01088 } 01089 if (AST_LIST_EMPTY(sub2)) { 01090 /* The remaining sublist goes onto the list. */ 01091 AST_LIST_APPEND_LIST(list, sub1, node); 01092 break; 01093 } 01094 01095 if (mm_atexit_cmp(AST_LIST_FIRST(sub1), AST_LIST_FIRST(sub2)) <= 0) { 01096 reg = AST_LIST_REMOVE_HEAD(sub1, node); 01097 } else { 01098 reg = AST_LIST_REMOVE_HEAD(sub2, node); 01099 } 01100 AST_LIST_INSERT_TAIL(list, reg, node); 01101 } 01102 }
static void mm_atexit_list_sort | ( | struct region_list * | list, | |
size_t | length | |||
) | [static] |
Semi-sorted merged list.
Sublists to merge. (Can only merge two sublists at this time.)
Sublist size.
Remaining elements in the list.
Number of sublist merge passes to process the list.
Definition at line 1150 of file astmm.c.
References ARRAY_LEN, AST_LIST_APPEND_LIST, AST_LIST_EMPTY, AST_LIST_HEAD_NOLOCK_INIT_VALUE, mm_atexit_list_merge(), and mm_atexit_list_split().
Referenced by mm_atexit_dump().
01151 { 01152 /*! Semi-sorted merged list. */ 01153 struct region_list merged = AST_LIST_HEAD_NOLOCK_INIT_VALUE; 01154 /*! Sublists to merge. (Can only merge two sublists at this time.) */ 01155 struct region_list sub[2] = { 01156 AST_LIST_HEAD_NOLOCK_INIT_VALUE, 01157 AST_LIST_HEAD_NOLOCK_INIT_VALUE 01158 }; 01159 /*! Sublist size. */ 01160 size_t size = 1; 01161 /*! Remaining elements in the list. */ 01162 size_t remaining; 01163 /*! Number of sublist merge passes to process the list. */ 01164 int passes; 01165 01166 for (;;) { 01167 remaining = length; 01168 01169 passes = 0; 01170 while (!AST_LIST_EMPTY(list)) { 01171 mm_atexit_list_split(list, sub, ARRAY_LEN(sub), size, &remaining); 01172 mm_atexit_list_merge(&merged, &sub[0], &sub[1]); 01173 ++passes; 01174 } 01175 AST_LIST_APPEND_LIST(list, &merged, node); 01176 if (passes <= 1) { 01177 /* The list is now sorted. */ 01178 break; 01179 } 01180 01181 /* Double the sublist size to remove for next round. */ 01182 size <<= 1; 01183 } 01184 }
static void mm_atexit_list_split | ( | struct region_list * | list, | |
struct region_list | sub[], | |||
size_t | num_lists, | |||
size_t | size, | |||
size_t * | remaining | |||
) | [static] |
Definition at line 1116 of file astmm.c.
References AST_LIST_APPEND_LIST, AST_LIST_INSERT_TAIL, and AST_LIST_REMOVE_HEAD.
Referenced by mm_atexit_list_sort().
01117 { 01118 int idx; 01119 01120 for (idx = 0; idx < num_lists; ++idx) { 01121 size_t count; 01122 01123 if (*remaining < size) { 01124 /* The remaining source list goes onto the sublist. */ 01125 AST_LIST_APPEND_LIST(&sub[idx], list, node); 01126 *remaining = 0; 01127 break; 01128 } 01129 01130 /* Take a sublist off the beginning of the source list. */ 01131 *remaining -= size; 01132 for (count = size; count--;) { 01133 struct ast_region *reg; 01134 01135 reg = AST_LIST_REMOVE_HEAD(list, node); 01136 AST_LIST_INSERT_TAIL(&sub[idx], reg, node); 01137 } 01138 } 01139 }
static void mm_atexit_regions_list | ( | struct region_list * | alloced | ) | [static] |
Definition at line 1194 of file astmm.c.
References AST_LIST_TRAVERSE, astmm_log, ast_region::cache, ast_region::data, ast_region::file, ast_region::func, ast_region::len, and ast_region::lineno.
Referenced by mm_atexit_dump().
01195 { 01196 struct ast_region *reg; 01197 01198 AST_LIST_TRAVERSE(alloced, reg, node) { 01199 astmm_log("%s %s() line %u: %u bytes%s at %p\n", 01200 reg->file, reg->func, reg->lineno, 01201 (unsigned int) reg->len, reg->cache ? " (cache)" : "", reg->data); 01202 } 01203 }
static void mm_atexit_regions_summary | ( | struct region_list * | alloced | ) | [static] |
Definition at line 1213 of file astmm.c.
References AST_LIST_NEXT, AST_LIST_TRAVERSE, astmm_log, ast_region::cache, ast_region::file, ast_region::func, ast_region::len, ast_region::lineno, ast_region::next, SUMMARY_BY_FILE, SUMMARY_BY_FUNC, SUMMARY_BY_LINE, and total.
Referenced by mm_atexit_dump().
01214 { 01215 struct ast_region *reg; 01216 struct ast_region *next; 01217 struct { 01218 unsigned int count; 01219 unsigned int len; 01220 unsigned int cache_len; 01221 } by_line, by_func, by_file, total; 01222 01223 by_line.count = 0; 01224 by_line.len = 0; 01225 by_line.cache_len = 0; 01226 01227 by_func.count = 0; 01228 by_func.len = 0; 01229 by_func.cache_len = 0; 01230 01231 by_file.count = 0; 01232 by_file.len = 0; 01233 by_file.cache_len = 0; 01234 01235 total.count = 0; 01236 total.len = 0; 01237 total.cache_len = 0; 01238 01239 AST_LIST_TRAVERSE(alloced, reg, node) { 01240 next = AST_LIST_NEXT(reg, node); 01241 01242 ++by_line.count; 01243 by_line.len += reg->len; 01244 if (reg->cache) { 01245 by_line.cache_len += reg->len; 01246 } 01247 if (next && !strcmp(reg->file, next->file) && reg->lineno == next->lineno) { 01248 continue; 01249 } 01250 if (atexit_summary & SUMMARY_BY_LINE) { 01251 if (by_line.cache_len) { 01252 astmm_log("%10u bytes (%u in caches) in %u allocations. %s %s() line %u\n", 01253 by_line.len, by_line.cache_len, by_line.count, reg->file, reg->func, reg->lineno); 01254 } else { 01255 astmm_log("%10u bytes in %5u allocations. %s %s() line %u\n", 01256 by_line.len, by_line.count, reg->file, reg->func, reg->lineno); 01257 } 01258 } 01259 01260 by_func.count += by_line.count; 01261 by_func.len += by_line.len; 01262 by_func.cache_len += by_line.cache_len; 01263 by_line.count = 0; 01264 by_line.len = 0; 01265 by_line.cache_len = 0; 01266 if (next && !strcmp(reg->file, next->file) && !strcmp(reg->func, next->func)) { 01267 continue; 01268 } 01269 if (atexit_summary & SUMMARY_BY_FUNC) { 01270 if (by_func.cache_len) { 01271 astmm_log("%10u bytes (%u in caches) in %u allocations. %s %s()\n", 01272 by_func.len, by_func.cache_len, by_func.count, reg->file, reg->func); 01273 } else { 01274 astmm_log("%10u bytes in %5u allocations. %s %s()\n", 01275 by_func.len, by_func.count, reg->file, reg->func); 01276 } 01277 } 01278 01279 by_file.count += by_func.count; 01280 by_file.len += by_func.len; 01281 by_file.cache_len += by_func.cache_len; 01282 by_func.count = 0; 01283 by_func.len = 0; 01284 by_func.cache_len = 0; 01285 if (next && !strcmp(reg->file, next->file)) { 01286 continue; 01287 } 01288 if (atexit_summary & SUMMARY_BY_FILE) { 01289 if (by_file.cache_len) { 01290 astmm_log("%10u bytes (%u in caches) in %u allocations. %s\n", 01291 by_file.len, by_file.cache_len, by_file.count, reg->file); 01292 } else { 01293 astmm_log("%10u bytes in %5u allocations. %s\n", 01294 by_file.len, by_file.count, reg->file); 01295 } 01296 } 01297 01298 total.count += by_file.count; 01299 total.len += by_file.len; 01300 total.cache_len += by_file.cache_len; 01301 by_file.count = 0; 01302 by_file.len = 0; 01303 by_file.cache_len = 0; 01304 } 01305 01306 if (total.cache_len) { 01307 astmm_log("%u bytes (%u in caches) in %u allocations.\n", 01308 total.len, total.cache_len, total.count); 01309 } else { 01310 astmm_log("%u bytes in %u allocations.\n", total.len, total.count); 01311 } 01312 }
static void my_do_crash | ( | void | ) | [static] |
Definition at line 192 of file astmm.c.
References ast_do_crash().
Referenced by __ast_free_region(), __ast_realloc(), region_check_fences(), and region_data_check().
00193 { 00194 /* 00195 * Give the logger a chance to get the message out, just in case 00196 * we abort(), or Asterisk crashes due to whatever problem just 00197 * happened. 00198 */ 00199 usleep(1); 00200 ast_do_crash(); 00201 }
static void region_check_fences | ( | struct ast_region * | reg | ) | [static] |
Definition at line 395 of file astmm.c.
References astmm_log, ast_region::data, FENCE_MAGIC, ast_region::file, ast_region::func, get_unaligned_uint32(), ast_region::len, ast_region::lineno, and my_do_crash().
Referenced by __ast_free_region(), handle_memory_show_allocations(), and regions_check_all_fences().
00396 { 00397 unsigned int *fence; 00398 00399 /* 00400 * We use the bytes just preceeding reg->data and not reg->fence 00401 * because there is likely to be padding between reg->fence and 00402 * reg->data for reg->data alignment. 00403 */ 00404 fence = (unsigned int *) (reg->data - sizeof(*fence)); 00405 if (*fence != FENCE_MAGIC) { 00406 astmm_log("WARNING: Low fence violation of %p allocated at %s %s() line %d\n", 00407 reg->data, reg->file, reg->func, reg->lineno); 00408 my_do_crash(); 00409 } 00410 fence = (unsigned int *) (reg->data + reg->len); 00411 if (get_unaligned_uint32(fence) != FENCE_MAGIC) { 00412 astmm_log("WARNING: High fence violation of %p allocated at %s %s() line %d\n", 00413 reg->data, reg->file, reg->func, reg->lineno); 00414 my_do_crash(); 00415 } 00416 }
static void region_data_check | ( | struct ast_region * | reg | ) | [static] |
Definition at line 276 of file astmm.c.
References astmm_log, ast_region::data, ast_region::fence, ast_region::file, FREED_MAGIC, ast_region::func, ast_region::len, ast_region::lineno, and my_do_crash().
Referenced by freed_regions_flush(), and region_free().
00277 { 00278 void *end; 00279 unsigned int *pos; 00280 00281 /* 00282 * Check the lower fence, the payload, and whatever amount of 00283 * the higher fence that falls into alignment with the payload. 00284 */ 00285 end = reg->data + reg->len; 00286 for (pos = ®->fence; (void *) pos <= end; ++pos) { 00287 if (*pos != FREED_MAGIC) { 00288 astmm_log("WARNING: Memory corrupted after free of %p allocated at %s %s() line %d\n", 00289 reg->data, reg->file, reg->func, reg->lineno); 00290 my_do_crash(); 00291 break; 00292 } 00293 } 00294 }
static void region_data_wipe | ( | struct ast_region * | reg | ) | [static] |
Definition at line 253 of file astmm.c.
References ast_region::data, ast_region::fence, FREED_MAGIC, and ast_region::len.
Referenced by region_free().
00254 { 00255 void *end; 00256 unsigned int *pos; 00257 00258 /* 00259 * Wipe the lower fence, the payload, and whatever amount of the 00260 * higher fence that falls into alignment with the payload. 00261 */ 00262 end = reg->data + reg->len; 00263 for (pos = ®->fence; (void *) pos <= end; ++pos) { 00264 *pos = FREED_MAGIC; 00265 } 00266 }
static struct ast_region* region_find | ( | void * | ptr | ) | [static, read] |
Definition at line 512 of file astmm.c.
References AST_LIST_NEXT, ast_region::data, HASH, and regions.
Referenced by __ast_realloc().
00513 { 00514 int hash; 00515 struct ast_region *reg; 00516 00517 hash = HASH(ptr); 00518 for (reg = regions[hash]; reg; reg = AST_LIST_NEXT(reg, node)) { 00519 if (reg->data == ptr) { 00520 break; 00521 } 00522 } 00523 00524 return reg; 00525 }
static void region_free | ( | struct ast_freed_regions * | freed, | |
struct ast_region * | reg | |||
) | [static] |
Definition at line 331 of file astmm.c.
References ARRAY_LEN, ast_mutex_lock, ast_mutex_unlock, free, ast_freed_regions::index, region_data_check(), region_data_wipe(), ast_freed_regions::regions, and reglock.
Referenced by __ast_free_region().
00332 { 00333 struct ast_region *old; 00334 00335 region_data_wipe(reg); 00336 00337 ast_mutex_lock(®lock); 00338 old = freed->regions[freed->index]; 00339 freed->regions[freed->index] = reg; 00340 00341 ++freed->index; 00342 if (ARRAY_LEN(freed->regions) <= freed->index) { 00343 freed->index = 0; 00344 } 00345 ast_mutex_unlock(®lock); 00346 00347 if (old) { 00348 region_data_check(old); 00349 free(old); 00350 } 00351 }
static struct ast_region* region_remove | ( | void * | ptr | ) | [static, read] |
Definition at line 362 of file astmm.c.
References AST_LIST_NEXT, ast_mutex_lock, ast_mutex_unlock, ast_region::data, HASH, regions, and reglock.
Referenced by __ast_free_region().
00363 { 00364 int hash; 00365 struct ast_region *reg; 00366 struct ast_region *prev = NULL; 00367 00368 hash = HASH(ptr); 00369 00370 ast_mutex_lock(®lock); 00371 for (reg = regions[hash]; reg; reg = AST_LIST_NEXT(reg, node)) { 00372 if (reg->data == ptr) { 00373 if (prev) { 00374 AST_LIST_NEXT(prev, node) = AST_LIST_NEXT(reg, node); 00375 } else { 00376 regions[hash] = AST_LIST_NEXT(reg, node); 00377 } 00378 break; 00379 } 00380 prev = reg; 00381 } 00382 ast_mutex_unlock(®lock); 00383 00384 return reg; 00385 }
static void regions_check_all_fences | ( | void | ) | [static] |
Definition at line 424 of file astmm.c.
References ARRAY_LEN, AST_LIST_NEXT, ast_mutex_lock, ast_mutex_unlock, region_check_fences(), regions, and reglock.
Referenced by handle_memory_show_allocations(), and mm_atexit_final().
00425 { 00426 int idx; 00427 struct ast_region *reg; 00428 00429 ast_mutex_lock(®lock); 00430 for (idx = 0; idx < ARRAY_LEN(regions); ++idx) { 00431 for (reg = regions[idx]; reg; reg = AST_LIST_NEXT(reg, node)) { 00432 region_check_fences(reg); 00433 } 00434 } 00435 ast_mutex_unlock(®lock); 00436 }
int atexit_list [static] |
enum summary_opts atexit_summary [static] |
struct ast_cli_entry cli_memory[] [static] |
struct ast_freed_regions minnows [static] |
Small memory blocks that have been freed.
Definition at line 127 of file astmm.c.
Referenced by __ast_free_region(), and mm_atexit_final().
struct ast_region* regions[SOME_PRIME] [static] |
Hash table of lists of active allocated memory regions.
Definition at line 109 of file astmm.c.
Referenced by __ast_alloc_region(), handle_memory_show_allocations(), handle_memory_show_summary(), mm_atexit_hash_list(), mm_atexit_hash_restore(), region_find(), region_remove(), and regions_check_all_fences().
ast_mutex_t reglock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 0 } [static] |
Tracking this mutex will cause infinite recursion, as the mutex tracking code allocates memory
Definition at line 149 of file astmm.c.
Referenced by __ast_alloc_region(), __ast_realloc(), freed_regions_flush(), handle_memory_show_allocations(), handle_memory_show_summary(), mm_atexit_final(), region_free(), region_remove(), and regions_check_all_fences().
struct ast_freed_regions whales [static] |
Large memory blocks that have been freed.
Definition at line 125 of file astmm.c.
Referenced by __ast_free_region(), and mm_atexit_final().