Mon May 14 04:43:01 2007

Asterisk developer's documentation


threadstorage.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2005, Digium, Inc.
00005  *
00006  * Kevin P. Fleming <kpfleming@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \brief Debugging support for thread-local-storage objects
00022  *
00023  * \author Kevin P. Fleming <kpfleming@digium.com>
00024  */
00025 
00026 #include "asterisk.h"
00027 
00028 #if defined(DEBUG_THREADLOCALS)
00029 
00030 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
00031 
00032 #include <stdio.h>
00033 #include <stdlib.h>
00034 #include <string.h>
00035 
00036 #include "asterisk/logger.h"
00037 #include "asterisk/strings.h"
00038 #include "asterisk/utils.h"
00039 #include "asterisk/threadstorage.h"
00040 #include "asterisk/linkedlists.h"
00041 #include "asterisk/cli.h"
00042 
00043 struct tls_object {
00044    void *key;
00045    size_t size;
00046    const char *file;
00047    const char *function;
00048    unsigned int line;
00049    pthread_t thread;
00050    AST_LIST_ENTRY(tls_object) entry;
00051 };
00052 
00053 static AST_LIST_HEAD_STATIC(tls_objects, tls_object);
00054 
00055 void __ast_threadstorage_object_add(void *key, size_t len, const char *file, const char *function, unsigned int line)
00056 {
00057    struct tls_object *to;
00058 
00059    if (!(to = ast_calloc(sizeof(*to), 1)))
00060       return;
00061 
00062    to->key = key;
00063    to->size = len;
00064    to->file = file;
00065    to->function = function;
00066    to->line = line;
00067    to->thread = pthread_self();
00068 
00069    AST_LIST_LOCK(&tls_objects);
00070    AST_LIST_INSERT_TAIL(&tls_objects, to, entry);
00071    AST_LIST_UNLOCK(&tls_objects);
00072 }
00073 
00074 void __ast_threadstorage_object_remove(void *key)
00075 {
00076    struct tls_object *to;
00077 
00078    AST_LIST_LOCK(&tls_objects);
00079    AST_LIST_TRAVERSE_SAFE_BEGIN(&tls_objects, to, entry) {
00080       if (to->key == key) {
00081          AST_LIST_REMOVE_CURRENT(&tls_objects, entry);
00082          break;
00083       }
00084    }
00085    AST_LIST_TRAVERSE_SAFE_END;
00086    AST_LIST_UNLOCK(&tls_objects);
00087    if (to)
00088       free(to);
00089 }
00090 
00091 void __ast_threadstorage_object_replace(void *key_old, void *key_new, size_t len)
00092 {
00093    struct tls_object *to;
00094 
00095    AST_LIST_LOCK(&tls_objects);
00096    AST_LIST_TRAVERSE_SAFE_BEGIN(&tls_objects, to, entry) {
00097       if (to->key == key_old) {
00098          to->key = key_new;
00099          to->size = len;
00100          break;
00101       }
00102    }
00103    AST_LIST_TRAVERSE_SAFE_END;
00104    AST_LIST_UNLOCK(&tls_objects);
00105 }
00106 
00107 static int handle_show_allocations(int fd, int argc, char *argv[])
00108 {
00109    char *fn = NULL;
00110    size_t len = 0;
00111    unsigned int count = 0;
00112    struct tls_object *to;
00113 
00114    if (argc > 3)
00115       fn = argv[3];
00116 
00117    AST_LIST_LOCK(&tls_objects);
00118 
00119    AST_LIST_TRAVERSE(&tls_objects, to, entry) {
00120       if (fn && strcasecmp(to->file, fn))
00121          continue;
00122 
00123       ast_cli(fd, "%10d bytes allocated in %20s at line %5d of %25s (thread %p)\n",
00124          (int) to->size, to->function, to->line, to->file, (void *) to->thread);
00125       len += to->size;
00126       count++;
00127    }
00128 
00129    AST_LIST_UNLOCK(&tls_objects);
00130 
00131    ast_cli(fd, "%10d bytes allocated in %d allocation%s\n", (int) len, count, count > 1 ? "s" : "");
00132    
00133    return RESULT_SUCCESS;
00134 }
00135 
00136 static int handle_show_summary(int fd, int argc, char *argv[])
00137 {
00138    char *fn = NULL;
00139    size_t len = 0;
00140    unsigned int count = 0;
00141    struct tls_object *to;
00142    struct file {
00143       const char *name;
00144       size_t len;
00145       unsigned int count;
00146       AST_LIST_ENTRY(file) entry;
00147    } *file;
00148    AST_LIST_HEAD_NOLOCK_STATIC(file_summary, file);
00149 
00150    if (argc > 3)
00151       fn = argv[3];
00152 
00153    AST_LIST_LOCK(&tls_objects);
00154 
00155    AST_LIST_TRAVERSE(&tls_objects, to, entry) {
00156       if (fn && strcasecmp(to->file, fn))
00157          continue;
00158 
00159       AST_LIST_TRAVERSE(&file_summary, file, entry) {
00160          if ((!fn && (file->name == to->file)) || (fn && (file->name == to->function)))
00161             break;
00162       }
00163 
00164       if (!file) {
00165          file = alloca(sizeof(*file));
00166          memset(file, 0, sizeof(*file));
00167          file->name = fn ? to->function : to->file;
00168          AST_LIST_INSERT_TAIL(&file_summary, file, entry);
00169       }
00170 
00171       file->len += to->size;
00172       file->count++;
00173    }
00174 
00175    AST_LIST_UNLOCK(&tls_objects);
00176    
00177    AST_LIST_TRAVERSE(&file_summary, file, entry) {
00178       len += file->len;
00179       count += file->count;
00180       if (fn) {
00181          ast_cli(fd, "%10d bytes in %d allocation%ss in function %s\n",
00182             (int) file->len, file->count, file->count > 1 ? "s" : "", file->name);
00183       } else {
00184          ast_cli(fd, "%10d bytes in %d allocation%s in file %s\n",
00185             (int) file->len, file->count, file->count > 1 ? "s" : "", file->name);
00186       }
00187    }
00188 
00189    ast_cli(fd, "%10d bytes allocated in %d allocation%s\n", (int) len, count, count > 1 ? "s" : "");
00190    
00191    return RESULT_SUCCESS;
00192 }
00193 
00194 static struct ast_cli_entry cli[] = {
00195    {
00196       .cmda = { "threadstorage", "show", "allocations", NULL },
00197       .handler = handle_show_allocations,
00198       .summary = "Display outstanding thread local storage allocations",
00199       .usage =
00200       "Usage: threadstorage show allocations [<file>]\n"
00201       "       Dumps a list of all thread-specific memory allocations,\n"
00202       "optionally limited to those from a specific file\n",
00203    },
00204    {
00205       .cmda = { "threadstorage", "show", "summary", NULL },
00206       .handler = handle_show_summary,
00207       .summary = "Summarize outstanding memory allocations",
00208       .usage =
00209       "Usage: threadstorage show summary [<file>]\n"
00210       "       Summarizes thread-specific memory allocations by file, or optionally\n"
00211       "by function, if a file is specified\n",
00212    },
00213 };
00214 
00215 void threadstorage_init(void)
00216 {
00217    ast_cli_register_multiple(cli, sizeof(cli) / sizeof(cli[0]));
00218 }
00219 
00220 #else /* !defined(DEBUG_THREADLOCALS) */
00221 
00222 void threadstorage_init(void)
00223 {
00224 }
00225 
00226 #endif /* !defined(DEBUG_THREADLOCALS) */
00227 

Generated on Mon May 14 04:43:01 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.1