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_STATIC(tls_objects
, tls_object
);
55 void __ast_threadstorage_object_add(void *key
, size_t len
, const char *file
, const char *function
, unsigned int line
)
57 struct tls_object
*to
;
59 if (!(to
= ast_calloc(sizeof(*to
), 1)))
65 to
->function
= function
;
67 to
->thread
= pthread_self();
69 AST_LIST_LOCK(&tls_objects
);
70 AST_LIST_INSERT_TAIL(&tls_objects
, to
, entry
);
71 AST_LIST_UNLOCK(&tls_objects
);
74 void __ast_threadstorage_object_remove(void *key
)
76 struct tls_object
*to
;
78 AST_LIST_LOCK(&tls_objects
);
79 AST_LIST_TRAVERSE_SAFE_BEGIN(&tls_objects
, to
, entry
) {
81 AST_LIST_REMOVE_CURRENT(&tls_objects
, entry
);
85 AST_LIST_TRAVERSE_SAFE_END
;
86 AST_LIST_UNLOCK(&tls_objects
);
91 void __ast_threadstorage_object_replace(void *key_old
, void *key_new
, size_t len
)
93 struct tls_object
*to
;
95 AST_LIST_LOCK(&tls_objects
);
96 AST_LIST_TRAVERSE_SAFE_BEGIN(&tls_objects
, to
, entry
) {
97 if (to
->key
== key_old
) {
103 AST_LIST_TRAVERSE_SAFE_END
;
104 AST_LIST_UNLOCK(&tls_objects
);
107 static int handle_show_allocations(int fd
, int argc
, char *argv
[])
111 unsigned int count
= 0;
112 struct tls_object
*to
;
117 AST_LIST_LOCK(&tls_objects
);
119 AST_LIST_TRAVERSE(&tls_objects
, to
, entry
) {
120 if (fn
&& strcasecmp(to
->file
, fn
))
123 ast_cli(fd
, "%10d bytes allocated in %20s at line %5d of %25s (thread %p)\n",
124 (int) to
->size
, to
->function
, to
->line
, to
->file
, (void *) to
->thread
);
129 AST_LIST_UNLOCK(&tls_objects
);
131 ast_cli(fd
, "%10d bytes allocated in %d allocation%s\n", (int) len
, count
, count
> 1 ? "s" : "");
133 return RESULT_SUCCESS
;
136 static int handle_show_summary(int fd
, int argc
, char *argv
[])
140 unsigned int count
= 0;
141 struct tls_object
*to
;
146 AST_LIST_ENTRY(file
) entry
;
148 AST_LIST_HEAD_NOLOCK_STATIC(file_summary
, file
);
153 AST_LIST_LOCK(&tls_objects
);
155 AST_LIST_TRAVERSE(&tls_objects
, to
, entry
) {
156 if (fn
&& strcasecmp(to
->file
, fn
))
159 AST_LIST_TRAVERSE(&file_summary
, file
, entry
) {
160 if ((!fn
&& (file
->name
== to
->file
)) || (fn
&& (file
->name
== to
->function
)))
165 file
= alloca(sizeof(*file
));
166 memset(file
, 0, sizeof(*file
));
167 file
->name
= fn
? to
->function
: to
->file
;
168 AST_LIST_INSERT_TAIL(&file_summary
, file
, entry
);
171 file
->len
+= to
->size
;
175 AST_LIST_UNLOCK(&tls_objects
);
177 AST_LIST_TRAVERSE(&file_summary
, file
, entry
) {
179 count
+= file
->count
;
181 ast_cli(fd
, "%10d bytes in %d allocation%ss in function %s\n",
182 (int) file
->len
, file
->count
, file
->count
> 1 ? "s" : "", file
->name
);
184 ast_cli(fd
, "%10d bytes in %d allocation%s in file %s\n",
185 (int) file
->len
, file
->count
, file
->count
> 1 ? "s" : "", file
->name
);
189 ast_cli(fd
, "%10d bytes allocated in %d allocation%s\n", (int) len
, count
, count
> 1 ? "s" : "");
191 return RESULT_SUCCESS
;
194 static struct ast_cli_entry cli
[] = {
196 .cmda
= { "threadstorage", "show", "allocations", NULL
},
197 .handler
= handle_show_allocations
,
198 .summary
= "Display outstanding thread local storage allocations",
200 "Usage: threadstorage show allocations [<file>]\n"
201 " Dumps a list of all thread-specific memory allocations,\n"
202 "optionally limited to those from a specific file\n",
205 .cmda
= { "threadstorage", "show", "summary", NULL
},
206 .handler
= handle_show_summary
,
207 .summary
= "Summarize outstanding memory allocations",
209 "Usage: threadstorage show summary [<file>]\n"
210 " Summarizes thread-specific memory allocations by file, or optionally\n"
211 "by function, if a file is specified\n",
215 void threadstorage_init(void)
217 ast_cli_register_multiple(cli
, sizeof(cli
) / sizeof(cli
[0]));
220 #else /* !defined(DEBUG_THREADLOCALS) */
222 void threadstorage_init(void)
226 #endif /* !defined(DEBUG_THREADLOCALS) */