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>
28 #if defined(DEBUG_THREADLOCALS)
30 ASTERISK_FILE_VERSION(__FILE__
, "$Revision$")
36 #include "asterisk/logger.h"
37 #include "asterisk/strings.h"
38 #include "asterisk/utils.h"
39 #include "asterisk/threadstorage.h"
40 #include "asterisk/linkedlists.h"
41 #include "asterisk/cli.h"
50 AST_LIST_ENTRY(tls_object
) entry
;
53 static AST_LIST_HEAD_NOLOCK_STATIC(tls_objects
, tls_object
);
54 AST_MUTEX_DEFINE_STATIC_NOTRACKING(threadstoragelock
);
57 void __ast_threadstorage_object_add(void *key
, size_t len
, const char *file
, const char *function
, unsigned int line
)
59 struct tls_object
*to
;
61 if (!(to
= ast_calloc(1, sizeof(*to
))))
67 to
->function
= function
;
69 to
->thread
= pthread_self();
71 ast_mutex_lock(&threadstoragelock
);
72 AST_LIST_INSERT_TAIL(&tls_objects
, to
, entry
);
73 ast_mutex_unlock(&threadstoragelock
);
76 void __ast_threadstorage_object_remove(void *key
)
78 struct tls_object
*to
;
80 ast_mutex_lock(&threadstoragelock
);
81 AST_LIST_TRAVERSE_SAFE_BEGIN(&tls_objects
, to
, entry
) {
83 AST_LIST_REMOVE_CURRENT(&tls_objects
, entry
);
87 AST_LIST_TRAVERSE_SAFE_END
;
88 ast_mutex_unlock(&threadstoragelock
);
93 void __ast_threadstorage_object_replace(void *key_old
, void *key_new
, size_t len
)
95 struct tls_object
*to
;
97 ast_mutex_lock(&threadstoragelock
);
98 AST_LIST_TRAVERSE_SAFE_BEGIN(&tls_objects
, to
, entry
) {
99 if (to
->key
== key_old
) {
105 AST_LIST_TRAVERSE_SAFE_END
;
106 ast_mutex_unlock(&threadstoragelock
);
109 static int handle_show_allocations(int fd
, int argc
, char *argv
[])
113 unsigned int count
= 0;
114 struct tls_object
*to
;
119 ast_mutex_lock(&threadstoragelock
);
121 AST_LIST_TRAVERSE(&tls_objects
, to
, entry
) {
122 if (fn
&& strcasecmp(to
->file
, fn
))
125 ast_cli(fd
, "%10d bytes allocated in %20s at line %5d of %25s (thread %p)\n",
126 (int) to
->size
, to
->function
, to
->line
, to
->file
, (void *) to
->thread
);
131 ast_mutex_unlock(&threadstoragelock
);
133 ast_cli(fd
, "%10d bytes allocated in %d allocation%s\n", (int) len
, count
, count
> 1 ? "s" : "");
135 return RESULT_SUCCESS
;
138 static int handle_show_summary(int fd
, int argc
, char *argv
[])
142 unsigned int count
= 0;
143 struct tls_object
*to
;
148 AST_LIST_ENTRY(file
) entry
;
150 AST_LIST_HEAD_NOLOCK_STATIC(file_summary
, file
);
155 ast_mutex_lock(&threadstoragelock
);
157 AST_LIST_TRAVERSE(&tls_objects
, to
, entry
) {
158 if (fn
&& strcasecmp(to
->file
, fn
))
161 AST_LIST_TRAVERSE(&file_summary
, file
, entry
) {
162 if ((!fn
&& (file
->name
== to
->file
)) || (fn
&& (file
->name
== to
->function
)))
167 file
= alloca(sizeof(*file
));
168 memset(file
, 0, sizeof(*file
));
169 file
->name
= fn
? to
->function
: to
->file
;
170 AST_LIST_INSERT_TAIL(&file_summary
, file
, entry
);
173 file
->len
+= to
->size
;
177 ast_mutex_unlock(&threadstoragelock
);
179 AST_LIST_TRAVERSE(&file_summary
, file
, entry
) {
181 count
+= file
->count
;
183 ast_cli(fd
, "%10d bytes in %d allocation%ss in function %s\n",
184 (int) file
->len
, file
->count
, file
->count
> 1 ? "s" : "", file
->name
);
186 ast_cli(fd
, "%10d bytes in %d allocation%s in file %s\n",
187 (int) file
->len
, file
->count
, file
->count
> 1 ? "s" : "", file
->name
);
191 ast_cli(fd
, "%10d bytes allocated in %d allocation%s\n", (int) len
, count
, count
> 1 ? "s" : "");
193 return RESULT_SUCCESS
;
196 static struct ast_cli_entry cli
[] = {
198 .cmda
= { "threadstorage", "show", "allocations", NULL
},
199 .handler
= handle_show_allocations
,
200 .summary
= "Display outstanding thread local storage allocations",
202 "Usage: threadstorage show allocations [<file>]\n"
203 " Dumps a list of all thread-specific memory allocations,\n"
204 "optionally limited to those from a specific file\n",
207 .cmda
= { "threadstorage", "show", "summary", NULL
},
208 .handler
= handle_show_summary
,
209 .summary
= "Summarize outstanding memory allocations",
211 "Usage: threadstorage show summary [<file>]\n"
212 " Summarizes thread-specific memory allocations by file, or optionally\n"
213 "by function, if a file is specified\n",
217 void threadstorage_init(void)
219 ast_cli_register_multiple(cli
, sizeof(cli
) / sizeof(cli
[0]));
222 #else /* !defined(DEBUG_THREADLOCALS) */
224 void threadstorage_init(void)
228 #endif /* !defined(DEBUG_THREADLOCALS) */