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: 164736 $")
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
00055
00056 #undef pthread_mutex_t
00057 #undef pthread_mutex_lock
00058 #undef pthread_mutex_unlock
00059 #undef pthread_mutex_init
00060 #undef pthread_mutex_destroy
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070 static pthread_mutex_t threadstoragelock;
00071
00072 void __ast_threadstorage_object_add(void *key, size_t len, const char *file, const char *function, unsigned int line)
00073 {
00074 struct tls_object *to;
00075
00076 if (!(to = ast_calloc(1, sizeof(*to))))
00077 return;
00078
00079 to->key = key;
00080 to->size = len;
00081 to->file = file;
00082 to->function = function;
00083 to->line = line;
00084 to->thread = pthread_self();
00085
00086 pthread_mutex_lock(&threadstoragelock);
00087 AST_LIST_INSERT_TAIL(&tls_objects, to, entry);
00088 pthread_mutex_unlock(&threadstoragelock);
00089 }
00090
00091 void __ast_threadstorage_object_remove(void *key)
00092 {
00093 struct tls_object *to;
00094
00095 pthread_mutex_lock(&threadstoragelock);
00096 AST_LIST_TRAVERSE_SAFE_BEGIN(&tls_objects, to, entry) {
00097 if (to->key == key) {
00098 AST_LIST_REMOVE_CURRENT(&tls_objects, entry);
00099 break;
00100 }
00101 }
00102 AST_LIST_TRAVERSE_SAFE_END;
00103 pthread_mutex_unlock(&threadstoragelock);
00104 if (to)
00105 free(to);
00106 }
00107
00108 void __ast_threadstorage_object_replace(void *key_old, void *key_new, size_t len)
00109 {
00110 struct tls_object *to;
00111
00112 pthread_mutex_lock(&threadstoragelock);
00113 AST_LIST_TRAVERSE_SAFE_BEGIN(&tls_objects, to, entry) {
00114 if (to->key == key_old) {
00115 to->key = key_new;
00116 to->size = len;
00117 break;
00118 }
00119 }
00120 AST_LIST_TRAVERSE_SAFE_END;
00121 pthread_mutex_unlock(&threadstoragelock);
00122 }
00123
00124 static int handle_show_allocations(int fd, int argc, char *argv[])
00125 {
00126 char *fn = NULL;
00127 size_t len = 0;
00128 unsigned int count = 0;
00129 struct tls_object *to;
00130
00131 if (argc > 3)
00132 fn = argv[3];
00133
00134 pthread_mutex_lock(&threadstoragelock);
00135
00136 AST_LIST_TRAVERSE(&tls_objects, to, entry) {
00137 if (fn && strcasecmp(to->file, fn))
00138 continue;
00139
00140 ast_cli(fd, "%10d bytes allocated in %20s at line %5d of %25s (thread %p)\n",
00141 (int) to->size, to->function, to->line, to->file, (void *) to->thread);
00142 len += to->size;
00143 count++;
00144 }
00145
00146 pthread_mutex_unlock(&threadstoragelock);
00147
00148 ast_cli(fd, "%10d bytes allocated in %d allocation%s\n", (int) len, count, count > 1 ? "s" : "");
00149
00150 return RESULT_SUCCESS;
00151 }
00152
00153 static int handle_show_summary(int fd, int argc, char *argv[])
00154 {
00155 char *fn = NULL;
00156 size_t len = 0;
00157 unsigned int count = 0;
00158 struct tls_object *to;
00159 struct file {
00160 const char *name;
00161 size_t len;
00162 unsigned int count;
00163 AST_LIST_ENTRY(file) entry;
00164 } *file;
00165 AST_LIST_HEAD_NOLOCK_STATIC(file_summary, file);
00166
00167 if (argc > 3)
00168 fn = argv[3];
00169
00170 pthread_mutex_lock(&threadstoragelock);
00171
00172 AST_LIST_TRAVERSE(&tls_objects, to, entry) {
00173 if (fn && strcasecmp(to->file, fn))
00174 continue;
00175
00176 AST_LIST_TRAVERSE(&file_summary, file, entry) {
00177 if ((!fn && (file->name == to->file)) || (fn && (file->name == to->function)))
00178 break;
00179 }
00180
00181 if (!file) {
00182 file = alloca(sizeof(*file));
00183 memset(file, 0, sizeof(*file));
00184 file->name = fn ? to->function : to->file;
00185 AST_LIST_INSERT_TAIL(&file_summary, file, entry);
00186 }
00187
00188 file->len += to->size;
00189 file->count++;
00190 }
00191
00192 pthread_mutex_unlock(&threadstoragelock);
00193
00194 AST_LIST_TRAVERSE(&file_summary, file, entry) {
00195 len += file->len;
00196 count += file->count;
00197 if (fn) {
00198 ast_cli(fd, "%10d bytes in %d allocation%ss in function %s\n",
00199 (int) file->len, file->count, file->count > 1 ? "s" : "", file->name);
00200 } else {
00201 ast_cli(fd, "%10d bytes in %d allocation%s in file %s\n",
00202 (int) file->len, file->count, file->count > 1 ? "s" : "", file->name);
00203 }
00204 }
00205
00206 ast_cli(fd, "%10d bytes allocated in %d allocation%s\n", (int) len, count, count > 1 ? "s" : "");
00207
00208 return RESULT_SUCCESS;
00209 }
00210
00211 static struct ast_cli_entry cli[] = {
00212 {
00213 .cmda = { "threadstorage", "show", "allocations", NULL },
00214 .handler = handle_show_allocations,
00215 .summary = "Display outstanding thread local storage allocations",
00216 .usage =
00217 "Usage: threadstorage show allocations [<file>]\n"
00218 " Dumps a list of all thread-specific memory allocations,\n"
00219 "optionally limited to those from a specific file\n",
00220 },
00221 {
00222 .cmda = { "threadstorage", "show", "summary", NULL },
00223 .handler = handle_show_summary,
00224 .summary = "Summarize outstanding memory allocations",
00225 .usage =
00226 "Usage: threadstorage show summary [<file>]\n"
00227 " Summarizes thread-specific memory allocations by file, or optionally\n"
00228 "by function, if a file is specified\n",
00229 },
00230 };
00231
00232 void threadstorage_init(void)
00233 {
00234 pthread_mutex_init(&threadstoragelock, NULL);
00235 ast_cli_register_multiple(cli, sizeof(cli) / sizeof(cli[0]));
00236 }
00237
00238 #else
00239
00240 void threadstorage_init(void)
00241 {
00242 }
00243
00244 #endif
00245