Let's also include aclocal.m4
[asterisk-bristuff.git] / main / threadstorage.c
blob54b37b073cffa7ab38128eca6270200d299ba332
1 /*
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.
19 /*! \file
21 * \brief Debugging support for thread-local-storage objects
23 * \author Kevin P. Fleming <kpfleming@digium.com>
26 #include "asterisk.h"
28 #if defined(DEBUG_THREADLOCALS)
30 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
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"
43 struct tls_object {
44 void *key;
45 size_t size;
46 const char *file;
47 const char *function;
48 unsigned int line;
49 pthread_t thread;
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))))
62 return;
64 to->key = key;
65 to->size = len;
66 to->file = file;
67 to->function = function;
68 to->line = line;
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) {
82 if (to->key == key) {
83 AST_LIST_REMOVE_CURRENT(&tls_objects, entry);
84 break;
87 AST_LIST_TRAVERSE_SAFE_END;
88 ast_mutex_unlock(&threadstoragelock);
89 if (to)
90 free(to);
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) {
100 to->key = key_new;
101 to->size = len;
102 break;
105 AST_LIST_TRAVERSE_SAFE_END;
106 ast_mutex_unlock(&threadstoragelock);
109 static int handle_show_allocations(int fd, int argc, char *argv[])
111 char *fn = NULL;
112 size_t len = 0;
113 unsigned int count = 0;
114 struct tls_object *to;
116 if (argc > 3)
117 fn = argv[3];
119 ast_mutex_lock(&threadstoragelock);
121 AST_LIST_TRAVERSE(&tls_objects, to, entry) {
122 if (fn && strcasecmp(to->file, fn))
123 continue;
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);
127 len += to->size;
128 count++;
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[])
140 char *fn = NULL;
141 size_t len = 0;
142 unsigned int count = 0;
143 struct tls_object *to;
144 struct file {
145 const char *name;
146 size_t len;
147 unsigned int count;
148 AST_LIST_ENTRY(file) entry;
149 } *file;
150 AST_LIST_HEAD_NOLOCK_STATIC(file_summary, file);
152 if (argc > 3)
153 fn = argv[3];
155 ast_mutex_lock(&threadstoragelock);
157 AST_LIST_TRAVERSE(&tls_objects, to, entry) {
158 if (fn && strcasecmp(to->file, fn))
159 continue;
161 AST_LIST_TRAVERSE(&file_summary, file, entry) {
162 if ((!fn && (file->name == to->file)) || (fn && (file->name == to->function)))
163 break;
166 if (!file) {
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;
174 file->count++;
177 ast_mutex_unlock(&threadstoragelock);
179 AST_LIST_TRAVERSE(&file_summary, file, entry) {
180 len += file->len;
181 count += file->count;
182 if (fn) {
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);
185 } else {
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",
201 .usage =
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",
210 .usage =
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) */