Index: asterisk.c =================================================================== --- asterisk.c (revision 8193) +++ asterisk.c (working copy) @@ -264,6 +264,65 @@ free(find); } +struct thread_list_t { + AST_LIST_ENTRY(thread_list_t) list; + char *name; + const void *id; +}; + +static AST_LIST_HEAD_STATIC(thread_list, thread_list_t); + +static char show_threads_help[] = +"Usage: show threads\n" +" List threads currently active in the system.\n"; + +void ast_register_thread(char *name) +{ + struct thread_list_t *new = ast_calloc(1, sizeof(*new)); + + if (!new) + return; + new->id = pthread_self(); + new->name = name; /* this was a copy already */ + AST_LIST_LOCK(&thread_list); + AST_LIST_INSERT_HEAD(&thread_list, new, list); + AST_LIST_UNLOCK(&thread_list); +} + +void ast_unregister_thread(void *id) +{ + struct thread_list_t *x; + + AST_LIST_LOCK(&thread_list); + AST_LIST_TRAVERSE_SAFE_BEGIN(&thread_list, x, list) { + if (x->id == id) { + AST_LIST_REMOVE_CURRENT(&thread_list, list); + break; + } + } + AST_LIST_TRAVERSE_SAFE_END; + AST_LIST_UNLOCK(&thread_list); + if (x) { + free(x->name); + free(x); + } +} + +static int handle_show_threads(int fd, int argc, char *argv[]) +{ + int count = 0; + struct thread_list_t *cur; + + AST_LIST_LOCK(&thread_list); + AST_LIST_TRAVERSE(&thread_list, cur, list) { + ast_cli(fd, "%p %s\n", cur->id, cur->name); + count++; + } + AST_LIST_UNLOCK(&thread_list); + ast_cli(fd, "%d threads listed.\n", count); + return 0; +} + static char show_version_files_help[] = "Usage: show version files [like ]\n" " Shows the revision numbers of the files used to build this copy of Asterisk.\n" @@ -1231,6 +1289,8 @@ #if !defined(LOW_MEMORY) { { "show", "version", "files", NULL }, handle_show_version_files, "Show versions of files used to build Asterisk", show_version_files_help, complete_show_version_files }, + { { "show", "threads", NULL }, handle_show_threads, + "Show running threads", show_threads_help, NULL }, #endif /* ! LOW_MEMORY */ }; Index: utils.c =================================================================== --- utils.c (revision 8193) +++ utils.c (working copy) @@ -487,8 +505,31 @@ #undef pthread_create /* For ast_pthread_create function only */ #endif /* !__linux__ */ -int ast_pthread_create_stack(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *), void *data, size_t stacksize) +/* + * support for 'show threads'. The start routine is wrapped by + * dummy_start(), so that ast_register_thread() and + * ast_unregister_thread() know the thread identifier. + */ +struct thr_arg { + void *(*start_routine)(void *); + void *data; + char *name; +}; + +static void *dummy_start(void *data) { + struct thr_arg a = *((struct thr_arg *)data); /* make a local copy */ + free(data); + ast_register_thread(a.name); + pthread_cleanup_push(ast_unregister_thread, pthread_self()); /* on unregister */ + return a.start_routine(a.data); +} + +int ast_pthread_create_stack(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *), void *data, size_t stacksize, + const char *file, const char *caller, int line, const char *start_fn) +{ + struct thr_arg *a; + pthread_attr_t lattr; if (!attr) { pthread_attr_init(&lattr); @@ -512,6 +553,17 @@ errno = pthread_attr_setstacksize(attr, stacksize); if (errno) ast_log(LOG_WARNING, "pthread_attr_setstacksize returned non-zero: %s\n", strerror(errno)); + a = ast_malloc(sizeof(*a)); + if (!a) + ast_log(LOG_WARNING, "no memory, thread %s will not be listed\n", start_fn); + else { /* remap parameters */ + a->start_routine = start_routine; + a->data = data; + start_routine = dummy_start; + asprintf(&a->name, "%-20s started at [%5d] %s %s()", + start_fn, line, file, caller); + data = a; + } return pthread_create(thread, attr, start_routine, data); /* We're in ast_pthread_create, so it's okay */ } Index: include/asterisk/utils.h =================================================================== --- include/asterisk/utils.h (revision 8193) +++ include/asterisk/utils.h (working copy) @@ -222,9 +222,15 @@ } #define AST_STACKSIZE 256 * 1024 -#define ast_pthread_create(a,b,c,d) ast_pthread_create_stack(a,b,c,d,0) -int ast_pthread_create_stack(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *), void *data, size_t stacksize); +void ast_register_thread(char *name); +void ast_unregister_thread(void *id); + +#define ast_pthread_create(a,b,c,d) ast_pthread_create_stack(a,b,c,d,0, \ + __FILE__, __FUNCTION__, __LINE__, #c) +int ast_pthread_create_stack(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *), void *data, size_t stacksize, + const char *file, const char *caller, int line, const char *start_fn); + /*! \brief Process a string to find and replace characters \param start The string to analyze