Wed Jan 8 2020 09:49:51

Asterisk developer's documentation


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 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 397106 $")
42 
43 #include "asterisk/strings.h"
44 #include "asterisk/utils.h"
45 #include "asterisk/threadstorage.h"
46 #include "asterisk/linkedlists.h"
47 #include "asterisk/cli.h"
48 
49 struct tls_object {
50  void *key;
51  size_t size;
52  const char *file;
53  const char *function;
54  unsigned int line;
55  pthread_t thread;
56  AST_LIST_ENTRY(tls_object) entry;
57 };
58 
59 static AST_LIST_HEAD_NOLOCK_STATIC(tls_objects, tls_object);
60 
61 /* Allow direct use of pthread_mutex_t and friends */
62 #undef pthread_mutex_t
63 #undef pthread_mutex_lock
64 #undef pthread_mutex_unlock
65 #undef pthread_mutex_init
66 #undef pthread_mutex_destroy
67 
68 /*!
69  * \brief lock for the tls_objects list
70  *
71  * \note We can not use an ast_mutex_t for this. The reason is that this
72  * lock is used within the context of thread-local data destructors,
73  * and the ast_mutex_* API uses thread-local data. Allocating more
74  * thread-local data at that point just causes a memory leak.
75  */
76 static pthread_mutex_t threadstoragelock;
77 
78 void __ast_threadstorage_object_add(void *key, size_t len, const char *file, const char *function, unsigned int line)
79 {
80  struct tls_object *to;
81 
82  if (!(to = ast_calloc(1, sizeof(*to))))
83  return;
84 
85  to->key = key;
86  to->size = len;
87  to->file = file;
88  to->function = function;
89  to->line = line;
90  to->thread = pthread_self();
91 
92  pthread_mutex_lock(&threadstoragelock);
93  AST_LIST_INSERT_TAIL(&tls_objects, to, entry);
94  pthread_mutex_unlock(&threadstoragelock);
95 }
96 
97 void __ast_threadstorage_object_remove(void *key)
98 {
99  struct tls_object *to;
100 
101  pthread_mutex_lock(&threadstoragelock);
102  AST_LIST_TRAVERSE_SAFE_BEGIN(&tls_objects, to, entry) {
103  if (to->key == key) {
105  break;
106  }
107  }
109  pthread_mutex_unlock(&threadstoragelock);
110  if (to)
111  ast_free(to);
112 }
113 
114 void __ast_threadstorage_object_replace(void *key_old, void *key_new, size_t len)
115 {
116  struct tls_object *to;
117 
118  pthread_mutex_lock(&threadstoragelock);
119  AST_LIST_TRAVERSE_SAFE_BEGIN(&tls_objects, to, entry) {
120  if (to->key == key_old) {
121  to->key = key_new;
122  to->size = len;
123  break;
124  }
125  }
127  pthread_mutex_unlock(&threadstoragelock);
128 }
129 
130 static char *handle_cli_threadstorage_show_allocations(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
131 {
132  const char *fn = NULL;
133  size_t len = 0;
134  unsigned int count = 0;
135  struct tls_object *to;
136 
137  switch (cmd) {
138  case CLI_INIT:
139  e->command = "threadstorage show allocations";
140  e->usage =
141  "Usage: threadstorage show allocations [<file>]\n"
142  " Dumps a list of all thread-specific memory allocations,\n"
143  " optionally limited to those from a specific file\n";
144  return NULL;
145  case CLI_GENERATE:
146  return NULL;
147  }
148 
149  if (a->argc > 4)
150  return CLI_SHOWUSAGE;
151 
152  if (a->argc > 3)
153  fn = a->argv[3];
154 
155  pthread_mutex_lock(&threadstoragelock);
156 
157  AST_LIST_TRAVERSE(&tls_objects, to, entry) {
158  if (fn && strcasecmp(to->file, fn))
159  continue;
160 
161  ast_cli(a->fd, "%10d bytes allocated in %20s at line %5d of %25s (thread %p)\n",
162  (int) to->size, to->function, to->line, to->file, (void *) to->thread);
163  len += to->size;
164  count++;
165  }
166 
167  pthread_mutex_unlock(&threadstoragelock);
168 
169  ast_cli(a->fd, "%10d bytes allocated in %d allocation%s\n", (int) len, count, count > 1 ? "s" : "");
170 
171  return CLI_SUCCESS;
172 }
173 
174 static char *handle_cli_threadstorage_show_summary(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
175 {
176  const char *fn = NULL;
177  size_t len = 0;
178  unsigned int count = 0;
179  struct tls_object *to;
180  struct file {
181  const char *name;
182  size_t len;
183  unsigned int count;
184  AST_LIST_ENTRY(file) entry;
185  } *file;
186  AST_LIST_HEAD_NOLOCK_STATIC(file_summary, file);
187 
188  switch (cmd) {
189  case CLI_INIT:
190  e->command = "threadstorage show summary";
191  e->usage =
192  "Usage: threadstorage show summary [<file>]\n"
193  " Summarizes thread-specific memory allocations by file, or optionally\n"
194  " by function, if a file is specified\n";
195  return NULL;
196  case CLI_GENERATE:
197  return NULL;
198  }
199 
200  if (a->argc > 4)
201  return CLI_SHOWUSAGE;
202 
203  if (a->argc > 3)
204  fn = a->argv[3];
205 
206  pthread_mutex_lock(&threadstoragelock);
207 
208  AST_LIST_TRAVERSE(&tls_objects, to, entry) {
209  if (fn && strcasecmp(to->file, fn))
210  continue;
211 
212  AST_LIST_TRAVERSE(&file_summary, file, entry) {
213  if ((!fn && (file->name == to->file)) || (fn && (file->name == to->function)))
214  break;
215  }
216 
217  if (!file) {
218  file = ast_alloca(sizeof(*file));
219  memset(file, 0, sizeof(*file));
220  file->name = fn ? to->function : to->file;
221  AST_LIST_INSERT_TAIL(&file_summary, file, entry);
222  }
223 
224  file->len += to->size;
225  file->count++;
226  }
227 
228  pthread_mutex_unlock(&threadstoragelock);
229 
230  AST_LIST_TRAVERSE(&file_summary, file, entry) {
231  len += file->len;
232  count += file->count;
233  if (fn) {
234  ast_cli(a->fd, "%10d bytes in %d allocation%ss in function %s\n",
235  (int) file->len, file->count, file->count > 1 ? "s" : "", file->name);
236  } else {
237  ast_cli(a->fd, "%10d bytes in %d allocation%s in file %s\n",
238  (int) file->len, file->count, file->count > 1 ? "s" : "", file->name);
239  }
240  }
241 
242  ast_cli(a->fd, "%10d bytes allocated in %d allocation%s\n", (int) len, count, count > 1 ? "s" : "");
243 
244  return CLI_SUCCESS;
245 }
246 
247 static struct ast_cli_entry cli[] = {
248  AST_CLI_DEFINE(handle_cli_threadstorage_show_allocations, "Display outstanding thread local storage allocations"),
249  AST_CLI_DEFINE(handle_cli_threadstorage_show_summary, "Summarize outstanding memory allocations")
250 };
251 
252 static void threadstorage_shutdown(void)
253 {
255 }
256 
257 void threadstorage_init(void)
258 {
259  pthread_mutex_init(&threadstoragelock, NULL);
261  ast_register_atexit(threadstorage_shutdown);
262 }
263 
264 #endif /* !defined(DEBUG_THREADLOCALS) */
265 
pthread_t thread
Definition: app_meetme.c:962
#define pthread_mutex_init
Definition: lock.h:559
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:191
Asterisk main include file. File version handling, generic pbx functions.
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: utils.h:653
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: cli.c:2177
descriptor for a cli entry.
Definition: cli.h:165
const int argc
Definition: cli.h:154
switch(yytype)
Definition: ast_expr2.c:1510
Definition: cli.h:146
Definitions to aid in the use of thread local storage.
void ast_cli(int fd, const char *fmt,...)
Definition: cli.c:105
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:600
#define pthread_mutex_t
Definition: lock.h:553
Utility functions.
#define pthread_mutex_lock
Definition: lock.h:556
const int fd
Definition: cli.h:153
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:554
int ast_register_atexit(void(*func)(void))
Register a function to be executed before Asterisk exits.
Definition: asterisk.c:998
A set of macros to manage forward-linked lists.
static struct ast_cli_entry cli[]
Definition: codec_dahdi.c:69
const char *const * argv
Definition: cli.h:155
#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:716
#define CLI_SHOWUSAGE
Definition: cli.h:44
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[]
#define ast_free(a)
Definition: astmm.h:97
char * command
Definition: cli.h:180
Prototypes for public functions only of internal interest,.
const char * usage
Definition: cli.h:171
#define CLI_SUCCESS
Definition: cli.h:43
void threadstorage_init(void)
Definition: threadstorage.c:35
Standard Command Line Interface.
#define ast_calloc(a, b)
Definition: astmm.h:82
int ast_cli_register_multiple(struct ast_cli_entry *e, int len)
Register multiple commands.
Definition: cli.c:2167
#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:557
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
Definition: asterisk.h:180