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