00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "asterisk.h"
00027
00028 #if defined(DEBUG_THREADLOCALS)
00029
00030 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 91192 $")
00031
00032 #include <stdio.h>
00033 #include <stdlib.h>
00034 #include <string.h>
00035
00036 #include "asterisk/logger.h"
00037 #include "asterisk/strings.h"
00038 #include "asterisk/utils.h"
00039 #include "asterisk/threadstorage.h"
00040 #include "asterisk/linkedlists.h"
00041 #include "asterisk/cli.h"
00042
00043 struct tls_object {
00044 void *key;
00045 size_t size;
00046 const char *file;
00047 const char *function;
00048 unsigned int line;
00049 pthread_t thread;
00050 AST_LIST_ENTRY(tls_object) entry;
00051 };
00052
00053 static AST_LIST_HEAD_NOLOCK_STATIC(tls_objects, tls_object);
00054 AST_MUTEX_DEFINE_STATIC_NOTRACKING(threadstoragelock);
00055
00056
00057 void __ast_threadstorage_object_add(void *key, size_t len, const char *file, const char *function, unsigned int line)
00058 {
00059 struct tls_object *to;
00060
00061 if (!(to = ast_calloc(1, sizeof(*to))))
00062 return;
00063
00064 to->key = key;
00065 to->size = len;
00066 to->file = file;
00067 to->function = function;
00068 to->line = line;
00069 to->thread = pthread_self();
00070
00071 ast_mutex_lock(&threadstoragelock);
00072 AST_LIST_INSERT_TAIL(&tls_objects, to, entry);
00073 ast_mutex_unlock(&threadstoragelock);
00074 }
00075
00076 void __ast_threadstorage_object_remove(void *key)
00077 {
00078 struct tls_object *to;
00079
00080 ast_mutex_lock(&threadstoragelock);
00081 AST_LIST_TRAVERSE_SAFE_BEGIN(&tls_objects, to, entry) {
00082 if (to->key == key) {
00083 AST_LIST_REMOVE_CURRENT(&tls_objects, entry);
00084 break;
00085 }
00086 }
00087 AST_LIST_TRAVERSE_SAFE_END;
00088 ast_mutex_unlock(&threadstoragelock);
00089 if (to)
00090 free(to);
00091 }
00092
00093 void __ast_threadstorage_object_replace(void *key_old, void *key_new, size_t len)
00094 {
00095 struct tls_object *to;
00096
00097 ast_mutex_lock(&threadstoragelock);
00098 AST_LIST_TRAVERSE_SAFE_BEGIN(&tls_objects, to, entry) {
00099 if (to->key == key_old) {
00100 to->key = key_new;
00101 to->size = len;
00102 break;
00103 }
00104 }
00105 AST_LIST_TRAVERSE_SAFE_END;
00106 ast_mutex_unlock(&threadstoragelock);
00107 }
00108
00109 static int handle_show_allocations(int fd, int argc, char *argv[])
00110 {
00111 char *fn = NULL;
00112 size_t len = 0;
00113 unsigned int count = 0;
00114 struct tls_object *to;
00115
00116 if (argc > 3)
00117 fn = argv[3];
00118
00119 ast_mutex_lock(&threadstoragelock);
00120
00121 AST_LIST_TRAVERSE(&tls_objects, to, entry) {
00122 if (fn && strcasecmp(to->file, fn))
00123 continue;
00124
00125 ast_cli(fd, "%10d bytes allocated in %20s at line %5d of %25s (thread %p)\n",
00126 (int) to->size, to->function, to->line, to->file, (void *) to->thread);
00127 len += to->size;
00128 count++;
00129 }
00130
00131 ast_mutex_unlock(&threadstoragelock);
00132
00133 ast_cli(fd, "%10d bytes allocated in %d allocation%s\n", (int) len, count, count > 1 ? "s" : "");
00134
00135 return RESULT_SUCCESS;
00136 }
00137
00138 static int handle_show_summary(int fd, int argc, char *argv[])
00139 {
00140 char *fn = NULL;
00141 size_t len = 0;
00142 unsigned int count = 0;
00143 struct tls_object *to;
00144 struct file {
00145 const char *name;
00146 size_t len;
00147 unsigned int count;
00148 AST_LIST_ENTRY(file) entry;
00149 } *file;
00150 AST_LIST_HEAD_NOLOCK_STATIC(file_summary, file);
00151
00152 if (argc > 3)
00153 fn = argv[3];
00154
00155 ast_mutex_lock(&threadstoragelock);
00156
00157 AST_LIST_TRAVERSE(&tls_objects, to, entry) {
00158 if (fn && strcasecmp(to->file, fn))
00159 continue;
00160
00161 AST_LIST_TRAVERSE(&file_summary, file, entry) {
00162 if ((!fn && (file->name == to->file)) || (fn && (file->name == to->function)))
00163 break;
00164 }
00165
00166 if (!file) {
00167 file = alloca(sizeof(*file));
00168 memset(file, 0, sizeof(*file));
00169 file->name = fn ? to->function : to->file;
00170 AST_LIST_INSERT_TAIL(&file_summary, file, entry);
00171 }
00172
00173 file->len += to->size;
00174 file->count++;
00175 }
00176
00177 ast_mutex_unlock(&threadstoragelock);
00178
00179 AST_LIST_TRAVERSE(&file_summary, file, entry) {
00180 len += file->len;
00181 count += file->count;
00182 if (fn) {
00183 ast_cli(fd, "%10d bytes in %d allocation%ss in function %s\n",
00184 (int) file->len, file->count, file->count > 1 ? "s" : "", file->name);
00185 } else {
00186 ast_cli(fd, "%10d bytes in %d allocation%s in file %s\n",
00187 (int) file->len, file->count, file->count > 1 ? "s" : "", file->name);
00188 }
00189 }
00190
00191 ast_cli(fd, "%10d bytes allocated in %d allocation%s\n", (int) len, count, count > 1 ? "s" : "");
00192
00193 return RESULT_SUCCESS;
00194 }
00195
00196 static struct ast_cli_entry cli[] = {
00197 {
00198 .cmda = { "threadstorage", "show", "allocations", NULL },
00199 .handler = handle_show_allocations,
00200 .summary = "Display outstanding thread local storage allocations",
00201 .usage =
00202 "Usage: threadstorage show allocations [<file>]\n"
00203 " Dumps a list of all thread-specific memory allocations,\n"
00204 "optionally limited to those from a specific file\n",
00205 },
00206 {
00207 .cmda = { "threadstorage", "show", "summary", NULL },
00208 .handler = handle_show_summary,
00209 .summary = "Summarize outstanding memory allocations",
00210 .usage =
00211 "Usage: threadstorage show summary [<file>]\n"
00212 " Summarizes thread-specific memory allocations by file, or optionally\n"
00213 "by function, if a file is specified\n",
00214 },
00215 };
00216
00217 void threadstorage_init(void)
00218 {
00219 ast_cli_register_multiple(cli, sizeof(cli) / sizeof(cli[0]));
00220 }
00221
00222 #else
00223
00224 void threadstorage_init(void)
00225 {
00226 }
00227
00228 #endif
00229