Asterisk - The Open Source Telephony Project GIT-master-f36a736
threadstorage.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 1999 - 2005, Digium, Inc.
5 *
6 * Kevin P. Fleming <kpfleming@digium.com>
7 *
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.
13 *
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.
17 */
18
19/*! \file
20 *
21 * \brief Debugging support for thread-local-storage objects
22 *
23 * \author Kevin P. Fleming <kpfleming@digium.com>
24 */
25
26/*** MODULEINFO
27 <support_level>core</support_level>
28 ***/
29
30#include "asterisk.h"
31#include "asterisk/_private.h"
32
33#if !defined(DEBUG_THREADLOCALS)
34
36{
37}
38
39#else /* !defined(DEBUG_THREADLOCALS) */
40
41#include "asterisk/strings.h"
42#include "asterisk/utils.h"
45#include "asterisk/cli.h"
46
47struct tls_object {
48 void *key;
49 size_t size;
50 const char *file;
51 const char *function;
52 unsigned int line;
53 pthread_t thread;
54 AST_LIST_ENTRY(tls_object) entry;
55};
56
57static AST_LIST_HEAD_NOLOCK_STATIC(tls_objects, tls_object);
58
59/* Allow direct use of pthread_mutex_t and friends */
60#undef pthread_mutex_t
61#undef pthread_mutex_lock
62#undef pthread_mutex_unlock
63#undef pthread_mutex_init
64#undef pthread_mutex_destroy
65
66/*!
67 * \brief lock for the tls_objects list
68 *
69 * \note We can not use an ast_mutex_t for this. The reason is that this
70 * lock is used within the context of thread-local data destructors,
71 * and the ast_mutex_* API uses thread-local data. Allocating more
72 * thread-local data at that point just causes a memory leak.
73 */
74static pthread_mutex_t threadstoragelock;
75
76void __ast_threadstorage_object_add(void *key, size_t len, const char *file, const char *function, unsigned int line)
77{
78 struct tls_object *to;
79
80 if (!(to = ast_calloc(1, sizeof(*to))))
81 return;
82
83 to->key = key;
84 to->size = len;
85 to->file = file;
86 to->function = function;
87 to->line = line;
88 to->thread = pthread_self();
89
90 pthread_mutex_lock(&threadstoragelock);
91 AST_LIST_INSERT_TAIL(&tls_objects, to, entry);
92 pthread_mutex_unlock(&threadstoragelock);
93}
94
95void __ast_threadstorage_object_remove(void *key)
96{
97 struct tls_object *to;
98
99 pthread_mutex_lock(&threadstoragelock);
100 AST_LIST_TRAVERSE_SAFE_BEGIN(&tls_objects, to, entry) {
101 if (to->key == key) {
103 break;
104 }
105 }
107 pthread_mutex_unlock(&threadstoragelock);
108 if (to)
109 ast_free(to);
110}
111
112void __ast_threadstorage_object_replace(void *key_old, void *key_new, size_t len)
113{
114 struct tls_object *to;
115
116 pthread_mutex_lock(&threadstoragelock);
117 AST_LIST_TRAVERSE_SAFE_BEGIN(&tls_objects, to, entry) {
118 if (to->key == key_old) {
119 to->key = key_new;
120 to->size = len;
121 break;
122 }
123 }
125 pthread_mutex_unlock(&threadstoragelock);
126}
127
128static char *handle_cli_threadstorage_show_allocations(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
129{
130 const char *fn = NULL;
131 size_t len = 0;
132 unsigned int count = 0;
133 struct tls_object *to;
134
135 switch (cmd) {
136 case CLI_INIT:
137 e->command = "threadstorage show allocations";
138 e->usage =
139 "Usage: threadstorage show allocations [<file>]\n"
140 " Dumps a list of all thread-specific memory allocations,\n"
141 " optionally limited to those from a specific file\n";
142 return NULL;
143 case CLI_GENERATE:
144 return NULL;
145 }
146
147 if (a->argc > 4)
148 return CLI_SHOWUSAGE;
149
150 if (a->argc > 3)
151 fn = a->argv[3];
152
153 pthread_mutex_lock(&threadstoragelock);
154
155 AST_LIST_TRAVERSE(&tls_objects, to, entry) {
156 if (fn && strcasecmp(to->file, fn))
157 continue;
158
159 ast_cli(a->fd, "%10d bytes allocated in %20s at line %5d of %25s (thread %p)\n",
160 (int) to->size, to->function, to->line, to->file, (void *) to->thread);
161 len += to->size;
162 count++;
163 }
164
165 pthread_mutex_unlock(&threadstoragelock);
166
167 ast_cli(a->fd, "%10d bytes allocated in %d allocation%s\n", (int) len, count, count > 1 ? "s" : "");
168
169 return CLI_SUCCESS;
170}
171
172static char *handle_cli_threadstorage_show_summary(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
173{
174 const char *fn = NULL;
175 size_t len = 0;
176 unsigned int count = 0;
177 struct tls_object *to;
178 struct file {
179 const char *name;
180 size_t len;
181 unsigned int count;
183 } *file;
184 AST_LIST_HEAD_NOLOCK_STATIC(file_summary, file);
185
186 switch (cmd) {
187 case CLI_INIT:
188 e->command = "threadstorage show summary";
189 e->usage =
190 "Usage: threadstorage show summary [<file>]\n"
191 " Summarizes thread-specific memory allocations by file, or optionally\n"
192 " by function, if a file is specified\n";
193 return NULL;
194 case CLI_GENERATE:
195 return NULL;
196 }
197
198 if (a->argc > 4)
199 return CLI_SHOWUSAGE;
200
201 if (a->argc > 3)
202 fn = a->argv[3];
203
204 pthread_mutex_lock(&threadstoragelock);
205
206 AST_LIST_TRAVERSE(&tls_objects, to, entry) {
207 if (fn && strcasecmp(to->file, fn))
208 continue;
209
210 AST_LIST_TRAVERSE(&file_summary, file, entry) {
211 if ((!fn && (file->name == to->file)) || (fn && (file->name == to->function)))
212 break;
213 }
214
215 if (!file) {
216 file = ast_alloca(sizeof(*file));
217 memset(file, 0, sizeof(*file));
218 file->name = fn ? to->function : to->file;
219 AST_LIST_INSERT_TAIL(&file_summary, file, entry);
220 }
221
222 file->len += to->size;
223 file->count++;
224 }
225
226 pthread_mutex_unlock(&threadstoragelock);
227
228 AST_LIST_TRAVERSE(&file_summary, file, entry) {
229 len += file->len;
230 count += file->count;
231 if (fn) {
232 ast_cli(a->fd, "%10d bytes in %d allocation%ss in function %s\n",
233 (int) file->len, file->count, file->count > 1 ? "s" : "", file->name);
234 } else {
235 ast_cli(a->fd, "%10d bytes in %d allocation%s in file %s\n",
236 (int) file->len, file->count, file->count > 1 ? "s" : "", file->name);
237 }
238 }
239
240 ast_cli(a->fd, "%10d bytes allocated in %d allocation%s\n", (int) len, count, count > 1 ? "s" : "");
241
242 return CLI_SUCCESS;
243}
244
245static struct ast_cli_entry cli[] = {
246 AST_CLI_DEFINE(handle_cli_threadstorage_show_allocations, "Display outstanding thread local storage allocations"),
247 AST_CLI_DEFINE(handle_cli_threadstorage_show_summary, "Summarize outstanding memory allocations")
248};
249
250static void threadstorage_shutdown(void)
251{
253}
254
255void threadstorage_init(void)
256{
257 pthread_mutex_init(&threadstoragelock, NULL);
259 ast_register_cleanup(threadstorage_shutdown);
260}
261
262#endif /* !defined(DEBUG_THREADLOCALS) */
Prototypes for public functions only of internal interest,.
pthread_t thread
Definition: app_sla.c:329
Asterisk main include file. File version handling, generic pbx functions.
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
Definition: clicompat.c:19
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:288
#define ast_free(a)
Definition: astmm.h:180
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
Standard Command Line Interface.
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_SUCCESS
Definition: cli.h:44
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
@ CLI_INIT
Definition: cli.h:152
@ CLI_GENERATE
Definition: cli.h:153
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
static struct ast_cli_entry cli[]
Definition: codec_dahdi.c:265
static const char name[]
Definition: format_mp3.c:68
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
A set of macros to manage forward-linked lists.
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
#define AST_LIST_HEAD_NOLOCK_STATIC(name, type)
Defines a structure to be used to hold a list of specified type, statically initialized.
Definition: linkedlists.h:346
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:410
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:529
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:557
#define pthread_mutex_lock
Definition: lock.h:625
#define pthread_mutex_t
Definition: lock.h:622
#define pthread_mutex_unlock
Definition: lock.h:626
#define pthread_mutex_init
Definition: lock.h:628
#define NULL
Definition: resample.c:96
String manipulation functions.
descriptor for a cli entry.
Definition: cli.h:171
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
Definition: search.h:40
static struct test_val a
void threadstorage_init(void)
Definition: threadstorage.c:35
Definitions to aid in the use of thread local storage.
Utility functions.
#define ARRAY_LEN(a)
Definition: utils.h:666