Mon Mar 31 07:38:05 2008

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_NOLOCK_STATIC(tls_objects, tls_object);
00054 AST_MUTEX_DEFINE_STATIC_NOTRACKING(threadstoragelock);
00055 
00056 
00057 void __ast_threadstorage_object_add(void *key, size_t len, const char *file, const char *function, unsigned int line)
00058 {
00059    struct tls_object *to;
00060 
00061    if (!(to = ast_calloc(1, sizeof(*to))))
00062       return;
00063 
00064    to->key = key;
00065    to->size = len;
00066    to->file = file;
00067    to->function = function;
00068    to->line = line;
00069    to->thread = pthread_self();
00070 
00071    ast_mutex_lock(&threadstoragelock);
00072    AST_LIST_INSERT_TAIL(&tls_objects, to, entry);
00073    ast_mutex_unlock(&threadstoragelock);
00074 }
00075 
00076 void __ast_threadstorage_object_remove(void *key)
00077 {
00078    struct tls_object *to;
00079 
00080    ast_mutex_lock(&threadstoragelock);
00081    AST_LIST_TRAVERSE_SAFE_BEGIN(&tls_objects, to, entry) {
00082       if (to->key == key) {
00083          AST_LIST_REMOVE_CURRENT(&tls_objects, entry);
00084          break;
00085       }
00086    }
00087    AST_LIST_TRAVERSE_SAFE_END;
00088    ast_mutex_unlock(&threadstoragelock);
00089    if (to)
00090       free(to);
00091 }
00092 
00093 void __ast_threadstorage_object_replace(void *key_old, void *key_new, size_t len)
00094 {
00095    struct tls_object *to;
00096 
00097    ast_mutex_lock(&threadstoragelock);
00098    AST_LIST_TRAVERSE_SAFE_BEGIN(&tls_objects, to, entry) {
00099       if (to->key == key_old) {
00100          to->key = key_new;
00101          to->size = len;
00102          break;
00103       }
00104    }
00105    AST_LIST_TRAVERSE_SAFE_END;
00106    ast_mutex_unlock(&threadstoragelock);
00107 }
00108 
00109 static int handle_show_allocations(int fd, int argc, char *argv[])
00110 {
00111    char *fn = NULL;
00112    size_t len = 0;
00113    unsigned int count = 0;
00114    struct tls_object *to;
00115 
00116    if (argc > 3)
00117       fn = argv[3];
00118 
00119    ast_mutex_lock(&threadstoragelock);
00120 
00121    AST_LIST_TRAVERSE(&tls_objects, to, entry) {
00122       if (fn && strcasecmp(to->file, fn))
00123          continue;
00124 
00125       ast_cli(fd, "%10d bytes allocated in %20s at line %5d of %25s (thread %p)\n",
00126          (int) to->size, to->function, to->line, to->file, (void *) to->thread);
00127       len += to->size;
00128       count++;
00129    }
00130 
00131    ast_mutex_unlock(&threadstoragelock);
00132 
00133    ast_cli(fd, "%10d bytes allocated in %d allocation%s\n", (int) len, count, count > 1 ? "s" : "");
00134    
00135    return RESULT_SUCCESS;
00136 }
00137 
00138 static int handle_show_summary(int fd, int argc, char *argv[])
00139 {
00140    char *fn = NULL;
00141    size_t len = 0;
00142    unsigned int count = 0;
00143    struct tls_object *to;
00144    struct file {
00145       const char *name;
00146       size_t len;
00147       unsigned int count;
00148       AST_LIST_ENTRY(file) entry;
00149    } *file;
00150    AST_LIST_HEAD_NOLOCK_STATIC(file_summary, file);
00151 
00152    if (argc > 3)
00153       fn = argv[3];
00154 
00155    ast_mutex_lock(&threadstoragelock);
00156 
00157    AST_LIST_TRAVERSE(&tls_objects, to, entry) {
00158       if (fn && strcasecmp(to->file, fn))
00159          continue;
00160 
00161       AST_LIST_TRAVERSE(&file_summary, file, entry) {
00162          if ((!fn && (file->name == to->file)) || (fn && (file->name == to->function)))
00163             break;
00164       }
00165 
00166       if (!file) {
00167          file = alloca(sizeof(*file));
00168          memset(file, 0, sizeof(*file));
00169          file->name = fn ? to->function : to->file;
00170          AST_LIST_INSERT_TAIL(&file_summary, file, entry);
00171       }
00172 
00173       file->len += to->size;
00174       file->count++;
00175    }
00176 
00177    ast_mutex_unlock(&threadstoragelock);
00178    
00179    AST_LIST_TRAVERSE(&file_summary, file, entry) {
00180       len += file->len;
00181       count += file->count;
00182       if (fn) {
00183          ast_cli(fd, "%10d bytes in %d allocation%ss in function %s\n",
00184             (int) file->len, file->count, file->count > 1 ? "s" : "", file->name);
00185       } else {
00186          ast_cli(fd, "%10d bytes in %d allocation%s in file %s\n",
00187             (int) file->len, file->count, file->count > 1 ? "s" : "", file->name);
00188       }
00189    }
00190 
00191    ast_cli(fd, "%10d bytes allocated in %d allocation%s\n", (int) len, count, count > 1 ? "s" : "");
00192    
00193    return RESULT_SUCCESS;
00194 }
00195 
00196 static struct ast_cli_entry cli[] = {
00197    {
00198       .cmda = { "threadstorage", "show", "allocations", NULL },
00199       .handler = handle_show_allocations,
00200       .summary = "Display outstanding thread local storage allocations",
00201       .usage =
00202       "Usage: threadstorage show allocations [<file>]\n"
00203       "       Dumps a list of all thread-specific memory allocations,\n"
00204       "optionally limited to those from a specific file\n",
00205    },
00206    {
00207       .cmda = { "threadstorage", "show", "summary", NULL },
00208       .handler = handle_show_summary,
00209       .summary = "Summarize outstanding memory allocations",
00210       .usage =
00211       "Usage: threadstorage show summary [<file>]\n"
00212       "       Summarizes thread-specific memory allocations by file, or optionally\n"
00213       "by function, if a file is specified\n",
00214    },
00215 };
00216 
00217 void threadstorage_init(void)
00218 {
00219    ast_cli_register_multiple(cli, sizeof(cli) / sizeof(cli[0]));
00220 }
00221 
00222 #else /* !defined(DEBUG_THREADLOCALS) */
00223 
00224 void threadstorage_init(void)
00225 {
00226 }
00227 
00228 #endif /* !defined(DEBUG_THREADLOCALS) */
00229 

Generated on Mon Mar 31 07:38:05 2008 for Asterisk - the Open Source PBX by  doxygen 1.5.1