2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2005, Digium, Inc.
6 * Kevin P. Fleming <kpfleming@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
21 * \brief Debugging support for thread-local-storage objects
23 * \author Kevin P. Fleming <kpfleming@digium.com>
27 <support_level>core</support_level>
31 #include "asterisk/_private.h"
33 #if !defined(DEBUG_THREADLOCALS)
35 void threadstorage_init(void)
39 #else /* !defined(DEBUG_THREADLOCALS) */
41 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
43 #include "asterisk/strings.h"
44 #include "asterisk/utils.h"
45 #include "asterisk/threadstorage.h"
46 #include "asterisk/linkedlists.h"
47 #include "asterisk/cli.h"
56 AST_LIST_ENTRY(tls_object) entry;
59 static AST_LIST_HEAD_NOLOCK_STATIC(tls_objects, tls_object);
61 /* Allow direct use of pthread_mutex_t and friends */
62 #undef pthread_mutex_t
63 #undef pthread_mutex_lock
64 #undef pthread_mutex_unlock
65 #undef pthread_mutex_init
66 #undef pthread_mutex_destroy
69 * \brief lock for the tls_objects list
71 * \note We can not use an ast_mutex_t for this. The reason is that this
72 * lock is used within the context of thread-local data destructors,
73 * and the ast_mutex_* API uses thread-local data. Allocating more
74 * thread-local data at that point just causes a memory leak.
76 static pthread_mutex_t threadstoragelock;
78 void __ast_threadstorage_object_add(void *key, size_t len, const char *file, const char *function, unsigned int line)
80 struct tls_object *to;
82 if (!(to = ast_calloc(1, sizeof(*to))))
88 to->function = function;
90 to->thread = pthread_self();
92 pthread_mutex_lock(&threadstoragelock);
93 AST_LIST_INSERT_TAIL(&tls_objects, to, entry);
94 pthread_mutex_unlock(&threadstoragelock);
97 void __ast_threadstorage_object_remove(void *key)
99 struct tls_object *to;
101 pthread_mutex_lock(&threadstoragelock);
102 AST_LIST_TRAVERSE_SAFE_BEGIN(&tls_objects, to, entry) {
103 if (to->key == key) {
104 AST_LIST_REMOVE_CURRENT(entry);
108 AST_LIST_TRAVERSE_SAFE_END;
109 pthread_mutex_unlock(&threadstoragelock);
114 void __ast_threadstorage_object_replace(void *key_old, void *key_new, size_t len)
116 struct tls_object *to;
118 pthread_mutex_lock(&threadstoragelock);
119 AST_LIST_TRAVERSE_SAFE_BEGIN(&tls_objects, to, entry) {
120 if (to->key == key_old) {
126 AST_LIST_TRAVERSE_SAFE_END;
127 pthread_mutex_unlock(&threadstoragelock);
130 static char *handle_cli_threadstorage_show_allocations(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
132 const char *fn = NULL;
134 unsigned int count = 0;
135 struct tls_object *to;
139 e->command = "threadstorage show allocations";
141 "Usage: threadstorage show allocations [<file>]\n"
142 " Dumps a list of all thread-specific memory allocations,\n"
143 " optionally limited to those from a specific file\n";
150 return CLI_SHOWUSAGE;
155 pthread_mutex_lock(&threadstoragelock);
157 AST_LIST_TRAVERSE(&tls_objects, to, entry) {
158 if (fn && strcasecmp(to->file, fn))
161 ast_cli(a->fd, "%10d bytes allocated in %20s at line %5d of %25s (thread %p)\n",
162 (int) to->size, to->function, to->line, to->file, (void *) to->thread);
167 pthread_mutex_unlock(&threadstoragelock);
169 ast_cli(a->fd, "%10d bytes allocated in %d allocation%s\n", (int) len, count, count > 1 ? "s" : "");
174 static char *handle_cli_threadstorage_show_summary(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
176 const char *fn = NULL;
178 unsigned int count = 0;
179 struct tls_object *to;
184 AST_LIST_ENTRY(file) entry;
186 AST_LIST_HEAD_NOLOCK_STATIC(file_summary, file);
190 e->command = "threadstorage show summary";
192 "Usage: threadstorage show summary [<file>]\n"
193 " Summarizes thread-specific memory allocations by file, or optionally\n"
194 " by function, if a file is specified\n";
201 return CLI_SHOWUSAGE;
206 pthread_mutex_lock(&threadstoragelock);
208 AST_LIST_TRAVERSE(&tls_objects, to, entry) {
209 if (fn && strcasecmp(to->file, fn))
212 AST_LIST_TRAVERSE(&file_summary, file, entry) {
213 if ((!fn && (file->name == to->file)) || (fn && (file->name == to->function)))
218 file = ast_alloca(sizeof(*file));
219 memset(file, 0, sizeof(*file));
220 file->name = fn ? to->function : to->file;
221 AST_LIST_INSERT_TAIL(&file_summary, file, entry);
224 file->len += to->size;
228 pthread_mutex_unlock(&threadstoragelock);
230 AST_LIST_TRAVERSE(&file_summary, file, entry) {
232 count += file->count;
234 ast_cli(a->fd, "%10d bytes in %d allocation%ss in function %s\n",
235 (int) file->len, file->count, file->count > 1 ? "s" : "", file->name);
237 ast_cli(a->fd, "%10d bytes in %d allocation%s in file %s\n",
238 (int) file->len, file->count, file->count > 1 ? "s" : "", file->name);
242 ast_cli(a->fd, "%10d bytes allocated in %d allocation%s\n", (int) len, count, count > 1 ? "s" : "");
247 static struct ast_cli_entry cli[] = {
248 AST_CLI_DEFINE(handle_cli_threadstorage_show_allocations, "Display outstanding thread local storage allocations"),
249 AST_CLI_DEFINE(handle_cli_threadstorage_show_summary, "Summarize outstanding memory allocations")
252 static void threadstorage_shutdown(void)
254 ast_cli_unregister_multiple(cli, ARRAY_LEN(cli));
257 void threadstorage_init(void)
259 pthread_mutex_init(&threadstoragelock, NULL);
260 ast_cli_register_multiple(cli, ARRAY_LEN(cli));
261 ast_register_atexit(threadstorage_shutdown);
264 #endif /* !defined(DEBUG_THREADLOCALS) */