Tue Aug 20 16:34:39 2013

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

Generated on 20 Aug 2013 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1