Wed Oct 28 11:45:42 2009

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 #include "asterisk/_private.h"
00028 
00029 #if !defined(DEBUG_THREADLOCALS)
00030 
00031 void threadstorage_init(void)
00032 {
00033 }
00034 
00035 #else /* !defined(DEBUG_THREADLOCALS) */
00036 
00037 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 164738 $")
00038 
00039 #include "asterisk/strings.h"
00040 #include "asterisk/utils.h"
00041 #include "asterisk/threadstorage.h"
00042 #include "asterisk/linkedlists.h"
00043 #include "asterisk/cli.h"
00044 
00045 struct tls_object {
00046    void *key;
00047    size_t size;
00048    const char *file;
00049    const char *function;
00050    unsigned int line;
00051    pthread_t thread;
00052    AST_LIST_ENTRY(tls_object) entry;
00053 };
00054 
00055 static AST_LIST_HEAD_NOLOCK_STATIC(tls_objects, tls_object);
00056 
00057 /* Allow direct use of pthread_mutex_t and friends */
00058 #undef pthread_mutex_t
00059 #undef pthread_mutex_lock
00060 #undef pthread_mutex_unlock
00061 #undef pthread_mutex_init
00062 #undef pthread_mutex_destroy
00063 
00064 /*!
00065  * \brief lock for the tls_objects list
00066  *
00067  * \note We can not use an ast_mutex_t for this.  The reason is that this
00068  *       lock is used within the context of thread-local data destructors,
00069  *       and the ast_mutex_* API uses thread-local data.  Allocating more
00070  *       thread-local data at that point just causes a memory leak.
00071  */
00072 static pthread_mutex_t threadstoragelock;
00073 
00074 void __ast_threadstorage_object_add(void *key, size_t len, const char *file, const char *function, unsigned int line)
00075 {
00076    struct tls_object *to;
00077 
00078    if (!(to = ast_calloc(1, sizeof(*to))))
00079       return;
00080 
00081    to->key = key;
00082    to->size = len;
00083    to->file = file;
00084    to->function = function;
00085    to->line = line;
00086    to->thread = pthread_self();
00087 
00088    pthread_mutex_lock(&threadstoragelock);
00089    AST_LIST_INSERT_TAIL(&tls_objects, to, entry);
00090    pthread_mutex_unlock(&threadstoragelock);
00091 }
00092 
00093 void __ast_threadstorage_object_remove(void *key)
00094 {
00095    struct tls_object *to;
00096 
00097    pthread_mutex_lock(&threadstoragelock);
00098    AST_LIST_TRAVERSE_SAFE_BEGIN(&tls_objects, to, entry) {
00099       if (to->key == key) {
00100          AST_LIST_REMOVE_CURRENT(entry);
00101          break;
00102       }
00103    }
00104    AST_LIST_TRAVERSE_SAFE_END;
00105    pthread_mutex_unlock(&threadstoragelock);
00106    if (to)
00107       ast_free(to);
00108 }
00109 
00110 void __ast_threadstorage_object_replace(void *key_old, void *key_new, size_t len)
00111 {
00112    struct tls_object *to;
00113 
00114    pthread_mutex_lock(&threadstoragelock);
00115    AST_LIST_TRAVERSE_SAFE_BEGIN(&tls_objects, to, entry) {
00116       if (to->key == key_old) {
00117          to->key = key_new;
00118          to->size = len;
00119          break;
00120       }
00121    }
00122    AST_LIST_TRAVERSE_SAFE_END;
00123    pthread_mutex_unlock(&threadstoragelock);
00124 }
00125 
00126 static char *handle_cli_threadstorage_show_allocations(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00127 {
00128    char *fn = NULL;
00129    size_t len = 0;
00130    unsigned int count = 0;
00131    struct tls_object *to;
00132 
00133    switch (cmd) {
00134    case CLI_INIT:
00135       e->command = "threadstorage show allocations";
00136       e->usage =
00137          "Usage: threadstorage show allocations [<file>]\n"
00138          "       Dumps a list of all thread-specific memory allocations,\n"
00139          "       optionally limited to those from a specific file\n";
00140       return NULL;
00141    case CLI_GENERATE:
00142       return NULL;
00143    }
00144 
00145    if (a->argc > 4)
00146       return CLI_SHOWUSAGE;
00147 
00148    if (a->argc > 3)
00149       fn = a->argv[3];
00150 
00151    pthread_mutex_lock(&threadstoragelock);
00152 
00153    AST_LIST_TRAVERSE(&tls_objects, to, entry) {
00154       if (fn && strcasecmp(to->file, fn))
00155          continue;
00156 
00157       ast_cli(a->fd, "%10d bytes allocated in %20s at line %5d of %25s (thread %p)\n",
00158          (int) to->size, to->function, to->line, to->file, (void *) to->thread);
00159       len += to->size;
00160       count++;
00161    }
00162 
00163    pthread_mutex_unlock(&threadstoragelock);
00164 
00165    ast_cli(a->fd, "%10d bytes allocated in %d allocation%s\n", (int) len, count, count > 1 ? "s" : "");
00166    
00167    return CLI_SUCCESS;
00168 }
00169 
00170 static char *handle_cli_threadstorage_show_summary(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00171 {
00172    char *fn = NULL;
00173    size_t len = 0;
00174    unsigned int count = 0;
00175    struct tls_object *to;
00176    struct file {
00177       const char *name;
00178       size_t len;
00179       unsigned int count;
00180       AST_LIST_ENTRY(file) entry;
00181    } *file;
00182    AST_LIST_HEAD_NOLOCK_STATIC(file_summary, file);
00183 
00184    switch (cmd) {
00185    case CLI_INIT:
00186       e->command = "threadstorage show summary";
00187       e->usage =
00188          "Usage: threadstorage show summary [<file>]\n"
00189          "       Summarizes thread-specific memory allocations by file, or optionally\n"
00190          "       by function, if a file is specified\n";
00191       return NULL;
00192    case CLI_GENERATE:
00193       return NULL;
00194    }
00195 
00196    if (a->argc > 4)
00197       return CLI_SHOWUSAGE;
00198 
00199    if (a->argc > 3)
00200       fn = a->argv[3];
00201 
00202    pthread_mutex_lock(&threadstoragelock);
00203 
00204    AST_LIST_TRAVERSE(&tls_objects, to, entry) {
00205       if (fn && strcasecmp(to->file, fn))
00206          continue;
00207 
00208       AST_LIST_TRAVERSE(&file_summary, file, entry) {
00209          if ((!fn && (file->name == to->file)) || (fn && (file->name == to->function)))
00210             break;
00211       }
00212 
00213       if (!file) {
00214          file = alloca(sizeof(*file));
00215          memset(file, 0, sizeof(*file));
00216          file->name = fn ? to->function : to->file;
00217          AST_LIST_INSERT_TAIL(&file_summary, file, entry);
00218       }
00219 
00220       file->len += to->size;
00221       file->count++;
00222    }
00223 
00224    pthread_mutex_unlock(&threadstoragelock);
00225    
00226    AST_LIST_TRAVERSE(&file_summary, file, entry) {
00227       len += file->len;
00228       count += file->count;
00229       if (fn) {
00230          ast_cli(a->fd, "%10d bytes in %d allocation%ss in function %s\n",
00231             (int) file->len, file->count, file->count > 1 ? "s" : "", file->name);
00232       } else {
00233          ast_cli(a->fd, "%10d bytes in %d allocation%s in file %s\n",
00234             (int) file->len, file->count, file->count > 1 ? "s" : "", file->name);
00235       }
00236    }
00237 
00238    ast_cli(a->fd, "%10d bytes allocated in %d allocation%s\n", (int) len, count, count > 1 ? "s" : "");
00239 
00240    return CLI_SUCCESS;
00241 }
00242 
00243 static struct ast_cli_entry cli[] = {
00244    AST_CLI_DEFINE(handle_cli_threadstorage_show_allocations, "Display outstanding thread local storage allocations"),
00245    AST_CLI_DEFINE(handle_cli_threadstorage_show_summary,     "Summarize outstanding memory allocations")
00246 };
00247 
00248 void threadstorage_init(void)
00249 {
00250    pthread_mutex_init(&threadstoragelock, NULL);
00251    ast_cli_register_multiple(cli, ARRAY_LEN(cli));
00252 }
00253 
00254 #endif /* !defined(DEBUG_THREADLOCALS) */
00255 

Generated on Wed Oct 28 11:45:43 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6