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