Sat Aug 6 00:39:32 2011

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

Generated on Sat Aug 6 00:39:32 2011 for Asterisk - the Open Source PBX by  doxygen 1.4.7