Asterisk - The Open Source Telephony Project  GIT-master-44aef04
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"
43 #include "asterisk/threadstorage.h"
44 #include "asterisk/linkedlists.h"
45 #include "asterisk/cli.h"
46 
47 struct 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 
57 static 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  */
74 static pthread_mutex_t threadstoragelock;
75 
76 void __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 
95 void __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 
112 void __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 
128 static 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 
172 static 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 
245 static 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 
250 static void threadstorage_shutdown(void)
251 {
253 }
254 
255 void threadstorage_init(void)
256 {
257  pthread_mutex_init(&threadstoragelock, NULL);
259  ast_register_cleanup(threadstorage_shutdown);
260 }
261 
262 #endif /* !defined(DEBUG_THREADLOCALS) */
pthread_t thread
Definition: app_meetme.c:1089
#define pthread_mutex_init
Definition: lock.h:626
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
Asterisk main include file. File version handling, generic pbx functions.
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
String manipulation functions.
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
descriptor for a cli entry.
Definition: cli.h:171
const int argc
Definition: cli.h:160
Definition: cli.h:152
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
#define NULL
Definition: resample.c:96
Definitions to aid in the use of thread local storage.
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:614
#define pthread_mutex_t
Definition: lock.h:620
Utility functions.
#define pthread_mutex_lock
Definition: lock.h:623
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
Definition: clicompat.c:19
const int fd
Definition: cli.h:159
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:556
A set of macros to manage forward-linked lists.
void threadstorage_init(void)
Definition: threadstorage.c:35
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:290
const char *const * argv
Definition: cli.h:161
#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:345
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:730
#define CLI_SHOWUSAGE
Definition: cli.h:45
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:409
static const char name[]
Definition: cdr_mysql.c:74
#define ast_free(a)
Definition: astmm.h:182
char * command
Definition: cli.h:186
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
Prototypes for public functions only of internal interest,.
const char * usage
Definition: cli.h:177
#define CLI_SUCCESS
Definition: cli.h:44
Standard Command Line Interface.
Definition: search.h:40
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:528
#define pthread_mutex_unlock
Definition: lock.h:624
static struct test_val a