[asterisk-commits] murf: branch murf/threadpool r148821 - in /team/murf/threadpool: include/aste...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Oct 14 08:21:55 CDT 2008


Author: murf
Date: Tue Oct 14 08:21:54 2008
New Revision: 148821

URL: http://svn.digium.com/view/asterisk?view=rev&rev=148821
Log:
I collected, over the last several weeks, several different
threadpool implementations in several languages, and gave
them a look-at.

And in the end, concluded that the threadpool implementation
in chan_iax2 was head and shoulders above all the others
for the purpose it serves in asterisk.

Most of the other implementations spent a good deal
of energy in providing a queue for jobs awaiting
threads. Submitting a thread involves (usually)
tossing into the queue, and the thread processor
takes any waiting jobs and assigns them to threads
independently.

Well, in Asterisk, this is silly. You can't wait
around for a thread. If there aren't enough threads,
you create a new DYNAMIC thread and get that job
going NOW. DYNAMIC threads are allowed to die if they
sit around unused too long. Otherwise, they get reused.

This DYNAMIC feature is the distinguishing mark of
the IAX2 threadpool implementation. 

In a typical fit of obsessive-compulsive behavior,
I nipped and tucked, I snipped and cut and
pasted, changed names to protect the innocent,
and made a fairly generic implementation out of the IAX2
threadpool code. You create them, and get back a 
pointer. You use that pointer to submit jobs.
You can several different threadpools. You can
set the func pointer in the pool itself, and 
make your threads homogeneous, or you can supply
a func to run in the run method, and make your
pool non-homogeneous. There's a "core show threadpools"
command that shows all your pools and threads (just like
IAX's "iax2 show threadpool", with only a slight diff.

All that's left to do is make pbx_start use a threadpool
to start its stuff, and eval the effect on chan_sip...
and see if the experiment is worth the effort!


Added:
    team/murf/threadpool/include/asterisk/threadpool.h   (with props)
    team/murf/threadpool/main/threadpool.c   (with props)
Modified:
    team/murf/threadpool/main/Makefile
    team/murf/threadpool/main/asterisk.c

Added: team/murf/threadpool/include/asterisk/threadpool.h
URL: http://svn.digium.com/view/asterisk/team/murf/threadpool/include/asterisk/threadpool.h?view=auto&rev=148821
==============================================================================
--- team/murf/threadpool/include/asterisk/threadpool.h (added)
+++ team/murf/threadpool/include/asterisk/threadpool.h Tue Oct 14 08:21:54 2008
@@ -1,0 +1,111 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2008, Digium, Inc.
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*!
+ * \file threadpool.h
+ * \author Russell Bryant <russell at digium.com>
+ * \brief Definitions to aid in the use of threadpools
+ *
+ * \arg \ref AstThreadPool
+ */
+
+/*!
+ * \page AstThreadPool The Asterisk Thread Pool API
+ *
+ * The motivation for using this code in Asterisk is for situations where
+ * many threads must be created in a short amount of time. Since
+ * thread creation can be very expensive, it is much better to keep
+ * set of threads that can be activated as needed. Such a need is
+ * evident when Asterisk is trying to handle large numbers of incoming
+ * calls.
+ *
+ * - \ref threadpool.h
+ */
+
+#ifndef ASTERISK_THREADPOOL_H
+#define ASTERISK_THREADPOOL_H
+
+#include "asterisk/utils.h"
+#include "asterisk/inline_api.h"
+
+/* Almost every bit of this was stolen blatantly from the 
+   IAX2 channel driver. */
+enum ast_threadpool_thread_iostate {
+	THREADPOOL_IOSTATE_IDLE,
+	THREADPOOL_IOSTATE_READY,
+	THREADPOOL_IOSTATE_PROCESSING,
+	THREADPOOL_IOSTATE_SCHEDREADY,
+};
+
+enum ast_threadpool_thread_type {
+	THREADPOOL_THREAD_TYPE_POOL,
+	THREADPOOL_THREAD_TYPE_DYNAMIC,
+};
+
+
+struct ast_pooledthread
+{
+	struct ast_threadpool *owning_pool;
+	enum ast_threadpool_thread_type type;
+	enum ast_threadpool_thread_iostate iostate;
+	int actions;
+	pthread_t threadid;
+	int threadnum;
+	unsigned int ready_for_signal:1;
+	time_t checktime;
+	ast_mutex_t lock;
+	ast_cond_t cond;
+	char curfunc[80];
+	void (*func)(void *);
+	void *funcdata;
+	AST_LIST_ENTRY(ast_pooledthread) list;
+};
+
+
+/*!
+ * \brief data for a thread locally stored variable
+ */
+struct ast_threadpool {
+	char *name;
+	int threadcount; /* the number of pre-allocated threads to create for the pool */
+	int max_threads;
+	int dynamic_msec;
+	void (*func)(void *);
+	char *funcname;
+	int dynamicthreadcount;
+	int dynamicthreadnum;
+	int activethreadcount;
+	AST_LIST_HEAD(idle_list, ast_pooledthread) idle_list;
+	AST_LIST_HEAD(active_list, ast_pooledthread) active_list;
+	AST_LIST_HEAD(dynamic_list, ast_pooledthread) dynamic_list;
+	AST_LIST_ENTRY(ast_threadpool) list;
+};
+
+void ast_threadpools_init(void);
+
+struct ast_threadpool *ast_threadpool_create(char *name, int num_threads, int max_threads, 
+											 int dynamic_msec, void (*func_to_run)(void*), char *funcname);
+
+int ast_threadpool_destroy(struct ast_threadpool *pool);
+
+void ast_threadpool_get_stats(struct ast_threadpool *pool, int *threads_activated, int *curr_active, 
+							  int *curr_dynamic, int *curr_avail);
+
+int ast_threadpool_run_default_func(struct ast_threadpool *pool, void *data);
+
+int ast_threadpool_run_this_func(struct ast_threadpool *pool, void (*func)(void *data), char *funcname, void *data);
+
+#endif

Propchange: team/murf/threadpool/include/asterisk/threadpool.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/murf/threadpool/include/asterisk/threadpool.h
------------------------------------------------------------------------------
    svn:keywords = Author Id Date Revision

Propchange: team/murf/threadpool/include/asterisk/threadpool.h
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: team/murf/threadpool/main/Makefile
URL: http://svn.digium.com/view/asterisk/team/murf/threadpool/main/Makefile?view=diff&rev=148821&r1=148820&r2=148821
==============================================================================
--- team/murf/threadpool/main/Makefile (original)
+++ team/murf/threadpool/main/Makefile Tue Oct 14 08:21:54 2008
@@ -28,7 +28,7 @@
 	cryptostub.o sha1.o http.o fixedjitterbuf.o abstract_jb.o \
 	strcompat.o threadstorage.o dial.o event.o adsistub.o audiohook.o \
 	astobj2.o hashtab.o global_datastores.o version.o \
-	features.o taskprocessor.o timing.o datastore.o
+	features.o taskprocessor.o timing.o datastore.o threadpool.o
 
 # we need to link in the objects statically, not as a library, because
 # otherwise modules will not have them available if none of the static

Modified: team/murf/threadpool/main/asterisk.c
URL: http://svn.digium.com/view/asterisk/team/murf/threadpool/main/asterisk.c?view=diff&rev=148821&r1=148820&r2=148821
==============================================================================
--- team/murf/threadpool/main/asterisk.c (original)
+++ team/murf/threadpool/main/asterisk.c Tue Oct 14 08:21:54 2008
@@ -117,6 +117,7 @@
 #include "asterisk/devicestate.h"
 #include "asterisk/module.h"
 #include "asterisk/dsp.h"
+#include "asterisk/threadpool.h"
 
 #include "asterisk/doxyref.h"		/* Doxygen documentation */
 
@@ -3342,6 +3343,8 @@
 
 	ast_channels_init();
 
+	ast_threadpools_init();
+
 	if (init_manager()) {
 		printf("%s", term_quit());
 		exit(1);

Added: team/murf/threadpool/main/threadpool.c
URL: http://svn.digium.com/view/asterisk/team/murf/threadpool/main/threadpool.c?view=auto&rev=148821
==============================================================================
--- team/murf/threadpool/main/threadpool.c (added)
+++ team/murf/threadpool/main/threadpool.c Tue Oct 14 08:21:54 2008
@@ -1,0 +1,482 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2008, Digium, Inc.
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Implementation of Threadpools with majority of code taken DIRECTLY from chan_iax2.c
+ *
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include <sys/mman.h>
+#include <dirent.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <sys/time.h>
+#include <sys/signal.h>
+#include <signal.h>
+#include <strings.h>
+#include <netdb.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <regex.h>
+
+#include "asterisk/paths.h"	/* need ast_config_AST_DATA_DIR for firmware */
+
+#include "asterisk/lock.h"
+#include "asterisk/frame.h" 
+#include "asterisk/channel.h"
+#include "asterisk/module.h"
+#include "asterisk/pbx.h"
+#include "asterisk/sched.h"
+#include "asterisk/io.h"
+#include "asterisk/config.h"
+#include "asterisk/cli.h"
+#include "asterisk/translate.h"
+#include "asterisk/md5.h"
+#include "asterisk/cdr.h"
+#include "asterisk/crypto.h"
+#include "asterisk/acl.h"
+#include "asterisk/manager.h"
+#include "asterisk/callerid.h"
+#include "asterisk/app.h"
+#include "asterisk/astdb.h"
+#include "asterisk/musiconhold.h"
+#include "asterisk/features.h"
+#include "asterisk/utils.h"
+#include "asterisk/causes.h"
+#include "asterisk/localtime.h"
+#include "asterisk/aes.h"
+#include "asterisk/dnsmgr.h"
+#include "asterisk/devicestate.h"
+#include "asterisk/netsock.h"
+#include "asterisk/stringfields.h"
+#include "asterisk/linkedlists.h"
+#include "asterisk/event.h"
+#include "asterisk/astobj2.h"
+#include "asterisk/timing.h"
+#include "asterisk/threadpool.h"
+
+
+static AST_LIST_HEAD_STATIC(pool_list, ast_threadpool);
+static void *threadpool_process_thread(void *data);
+
+
+/* WARNING: insert_idle_thread should only ever be called within the
+ * context of an threadpool_process_thread() thread.
+ */
+static void insert_idle_thread(struct ast_pooledthread *thread)
+{
+	struct ast_threadpool *pool = thread->owning_pool;
+	
+	if (thread->type == THREADPOOL_THREAD_TYPE_DYNAMIC) {
+		AST_LIST_LOCK(&pool->dynamic_list);
+		AST_LIST_INSERT_TAIL(&pool->dynamic_list, thread, list);
+		AST_LIST_UNLOCK(&pool->dynamic_list);
+	} else {
+		AST_LIST_LOCK(&pool->idle_list);
+		AST_LIST_INSERT_TAIL(&pool->idle_list, thread, list);
+		AST_LIST_UNLOCK(&pool->idle_list);
+	}
+
+	return;
+}
+
+static struct ast_pooledthread *find_idle_thread(void)
+{
+	struct ast_pooledthread *thread = NULL;
+	struct ast_threadpool *pool = thread->owning_pool;
+
+	/* Pop the head of the idle list off */
+	AST_LIST_LOCK(&pool->idle_list);
+	thread = AST_LIST_REMOVE_HEAD(&pool->idle_list, list);
+	AST_LIST_UNLOCK(&pool->idle_list);
+
+	/* If we popped a thread off the idle list, just return it */
+	if (thread) {
+		return thread;
+	}
+
+	/* Pop the head of the dynamic list off */
+	AST_LIST_LOCK(&pool->dynamic_list);
+	thread = AST_LIST_REMOVE_HEAD(&pool->dynamic_list, list);
+	AST_LIST_UNLOCK(&pool->dynamic_list);
+
+	/* If we popped a thread off the dynamic list, just return it */
+	if (thread) {
+		return thread;
+	}
+
+	/* If we can't create a new dynamic thread for any reason, return no thread at all */
+	if (pool->dynamicthreadcount >= pool->max_threads || !(thread = ast_calloc(1, sizeof(*thread))))
+		return NULL;
+
+	/* Set default values */
+	ast_atomic_fetchadd_int(&pool->dynamicthreadcount, 1);
+	thread->threadnum = ast_atomic_fetchadd_int(&pool->dynamicthreadnum, 1);
+	thread->type = THREADPOOL_THREAD_TYPE_DYNAMIC;
+
+	/* Initialize lock and condition */
+	ast_mutex_init(&thread->lock);
+	ast_cond_init(&thread->cond, NULL);
+
+	/* Create thread and send it on it's way */
+	if (ast_pthread_create_detached_background(&thread->threadid, NULL, threadpool_process_thread, thread)) {
+		ast_cond_destroy(&thread->cond);
+		ast_mutex_destroy(&thread->lock);
+		ast_free(thread);
+		return NULL;
+	}
+
+	/* Wait for the thread to be ready before returning it to the caller */
+	while (!thread->ready_for_signal)
+		usleep(1);
+
+	return thread;
+}
+
+/* Function to clean up process thread if it is cancelled */
+static void threadpool_process_thread_cleanup(void *data)
+{
+	struct ast_pooledthread *thread = data;
+	struct ast_threadpool *pool = thread->owning_pool;
+	ast_mutex_destroy(&(thread->lock));
+	ast_cond_destroy(&(thread->cond));
+	ast_free(thread);
+	ast_atomic_dec_and_test(&pool->activethreadcount);
+}
+
+static void *threadpool_process_thread(void *data)
+{
+	struct ast_pooledthread *thread = data;
+	struct timeval wait;
+	struct timespec ts;
+	int put_into_idle = 0;
+	struct ast_threadpool *pool = thread->owning_pool;
+
+	ast_atomic_fetchadd_int(&pool->activethreadcount,1);
+	pthread_cleanup_push(threadpool_process_thread_cleanup, data);
+	for(;;) {
+		/* Wait for something to signal us to be awake */
+		ast_mutex_lock(&thread->lock);
+
+		/* Flag that we're ready to accept signals */
+		thread->ready_for_signal = 1;
+		
+		/* Put into idle list if applicable */
+		if (put_into_idle)
+			insert_idle_thread(thread);
+
+		if (thread->type == THREADPOOL_THREAD_TYPE_DYNAMIC) {
+			struct ast_pooledthread *t = NULL;
+			/* Wait to be signalled or time out */
+			wait = ast_tvadd(ast_tvnow(), ast_samp2tv(30000, 1000));
+			ts.tv_sec = wait.tv_sec;
+			ts.tv_nsec = wait.tv_usec * 1000;
+			if (ast_cond_timedwait(&thread->cond, &thread->lock, &ts) == ETIMEDOUT) {
+				/* This thread was never put back into the available dynamic
+				 * thread list, so just go away. */
+				if (!put_into_idle) {
+					ast_mutex_unlock(&thread->lock);
+					break;
+				}
+				AST_LIST_LOCK(&pool->dynamic_list);
+				/* Account for the case where this thread is acquired *right* after a timeout */
+				if ((t = AST_LIST_REMOVE(&pool->dynamic_list, thread, list)))
+					ast_atomic_fetchadd_int(&pool->dynamicthreadcount, -1);
+				AST_LIST_UNLOCK(&pool->dynamic_list);
+				if (t) {
+					/* This dynamic thread timed out waiting for a task and was
+					 * not acquired immediately after the timeout, 
+					 * so it's time to go away. */
+					ast_mutex_unlock(&thread->lock);
+					break;
+				}
+				/* Someone grabbed our thread *right* after we timed out.
+				 * Wait for them to set us up with something to do and signal
+				 * us to continue. */
+				wait = ast_tvadd(ast_tvnow(), ast_samp2tv(30000, 1000));
+				ts.tv_sec = wait.tv_sec;
+				ts.tv_nsec = wait.tv_usec * 1000;
+				if (ast_cond_timedwait(&thread->cond, &thread->lock, &ts) == ETIMEDOUT)
+				{
+					ast_mutex_unlock(&thread->lock);
+					break;
+				}
+			}
+		} else {
+			ast_cond_wait(&thread->cond, &thread->lock);
+		}
+
+		/* Go back into our respective list */
+		put_into_idle = 1;
+
+		ast_mutex_unlock(&thread->lock);
+
+		if (thread->iostate == THREADPOOL_IOSTATE_IDLE)
+			continue;
+
+		/* Add ourselves to the active list now */
+		AST_LIST_LOCK(&pool->active_list);
+		AST_LIST_INSERT_HEAD(&pool->active_list, thread, list);
+		AST_LIST_UNLOCK(&pool->active_list);
+
+		/* See what we need to do */
+		switch(thread->iostate) {
+		case THREADPOOL_IOSTATE_READY:
+			thread->actions++;
+			thread->iostate = THREADPOOL_IOSTATE_PROCESSING;
+
+			/* call out func now */
+			if (thread->func)
+				(*thread->func)(thread->funcdata);
+			else
+				(*pool->func)(thread->funcdata);
+			break;
+		default:
+			break;
+		}
+		time(&thread->checktime);
+		thread->iostate = THREADPOOL_IOSTATE_IDLE;
+#ifdef DEBUG_SCHED_MULTITHREAD
+		thread->curfunc[0]='\0';
+#endif		
+
+		/* Now... remove ourselves from the active list, and return to the idle list */
+		AST_LIST_LOCK(&pool->active_list);
+		AST_LIST_REMOVE(&pool->active_list, thread, list);
+		AST_LIST_UNLOCK(&pool->active_list);
+
+	}
+
+	/*!\note For some reason, idle threads are exiting without being removed
+	 * from an idle list, which is causing memory corruption.  Forcibly remove
+	 * it from the list, if it's there.
+	 */
+	AST_LIST_LOCK(&pool->idle_list);
+	AST_LIST_REMOVE(&pool->idle_list, thread, list);
+	AST_LIST_UNLOCK(&pool->idle_list);
+
+	AST_LIST_LOCK(&pool->dynamic_list);
+	AST_LIST_REMOVE(&pool->dynamic_list, thread, list);
+	AST_LIST_UNLOCK(&pool->dynamic_list);
+
+	/* I am exiting here on my own volition, I need to clean up my own data structures
+	* Assume that I am no longer in any of the lists (idle, active, or dynamic)
+	*/
+	pthread_cleanup_pop(1);
+	return NULL;
+}
+
+struct ast_threadpool *ast_threadpool_create(char *name, int num_threads, int max_threads,
+											 int dynamic_msec, void (*def_func_to_run)(void *), 
+											 char *funcname)
+{
+	struct ast_threadpool *pool = ast_calloc(sizeof(struct ast_threadpool),1);
+	struct ast_pooledthread *thread;
+	int threadcount = 0;
+	int x;
+
+	pool->name = strdup(name);
+	pool->threadcount = num_threads;
+	pool->max_threads = max_threads;
+	pool->dynamic_msec = dynamic_msec;
+	pool->func = def_func_to_run;
+	/* put this struct in the list of pools so we can list them from the cli */
+	
+	/* start up the non-dynamic threads */
+	for (x = 0; x < pool->threadcount; x++) {
+		thread = ast_calloc(1, sizeof(*thread));
+		if (thread) {
+			thread->type = THREADPOOL_THREAD_TYPE_POOL;
+			thread->owning_pool = pool;
+			thread->threadnum = ++threadcount;
+			ast_mutex_init(&thread->lock);
+			ast_cond_init(&thread->cond, NULL);
+			if (ast_pthread_create_detached(&thread->threadid, NULL, threadpool_process_thread, thread)) {
+				ast_log(LOG_WARNING, "Failed to create new thread!\n");
+				ast_free(thread);
+				thread = NULL;
+			}
+			AST_LIST_LOCK(&pool->idle_list);
+			AST_LIST_INSERT_TAIL(&pool->idle_list, thread, list);
+			AST_LIST_UNLOCK(&pool->idle_list);
+		}
+	}
+	AST_LIST_LOCK(&pool_list);
+	AST_LIST_INSERT_TAIL(&pool_list, pool, list);
+	AST_LIST_UNLOCK(&pool_list);
+	return pool;
+}
+
+
+int ast_threadpool_destroy(struct ast_threadpool *pool)
+{
+	return 0;
+}
+
+
+void ast_threadpool_get_stats(struct ast_threadpool *pool, int *threads_activated, int *curr_active, 
+							  int *curr_dynamic, int *curr_avail)
+{
+}
+
+static void signal_condition(ast_mutex_t *lock, ast_cond_t *cond)
+{
+	ast_mutex_lock(lock);
+	ast_cond_signal(cond);
+	ast_mutex_unlock(lock);
+}
+
+int ast_threadpool_run_default_func(struct ast_threadpool *pool, void *data)
+{
+	struct ast_pooledthread *thread = NULL;
+	static time_t lasterror;
+	static time_t t;
+
+	thread = find_idle_thread();
+
+	if (thread != NULL) {
+		thread->func = pool->func;
+		thread->funcdata = data;
+		thread->iostate = THREADPOOL_IOSTATE_SCHEDREADY;
+		ast_copy_string(thread->curfunc, pool->funcname, sizeof(thread->curfunc));
+		signal_condition(&thread->lock, &thread->cond);
+		return 0;
+	}
+	time(&t);
+	if (t != lasterror) 
+		ast_debug(1, "Out of idle threadpool threads for scheduling!\n");
+	lasterror = t;
+
+	return -1;
+	
+}
+
+int ast_threadpool_run_this_func(struct ast_threadpool *pool, void (*func)(void *), char *funcname, void *data)
+{
+	struct ast_pooledthread *thread = NULL;
+	static time_t lasterror;
+	static time_t t;
+
+	thread = find_idle_thread();
+
+	if (thread != NULL) {
+		thread->func = func;
+		thread->funcdata = data;
+		ast_copy_string(thread->curfunc, funcname, sizeof(thread->curfunc));
+		thread->iostate = THREADPOOL_IOSTATE_SCHEDREADY;
+		signal_condition(&thread->lock, &thread->cond);
+		return 0;
+	}
+	time(&t);
+	if (t != lasterror) 
+		ast_debug(1, "Out of idle threadpool threads for scheduling!\n");
+	lasterror = t;
+
+	return -1;
+	
+}
+
+/* CLI stuff */
+
+static char *handle_cli_core_show_threadpools(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	struct ast_pooledthread *thread = NULL;
+	struct ast_threadpool *pool;
+	time_t t;
+	int threadcount = 0, dynamiccount = 0;
+	char type;
+
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "core show threadpools";
+		e->usage =
+			"Usage: core show threadpools\n"
+			"       Lists status of threadpools and their threads\n";
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;
+	}
+	if (a->argc != 3)
+		return CLI_SHOWUSAGE;
+		
+	AST_LIST_LOCK(&pool_list);
+	AST_LIST_TRAVERSE(&pool_list, pool, list) {
+		ast_cli(a->fd, "Information for the %s ThreadPool\n", pool->name);
+		time(&t);
+		ast_cli(a->fd, "Idle Threads:\n");
+		AST_LIST_LOCK(&pool->idle_list);
+		AST_LIST_TRAVERSE(&pool->idle_list, thread, list) {
+#ifdef DEBUG_SCHED_MULTITHREAD
+			ast_cli(a->fd, "Thread %d: state=%d, update=%d, actions=%d, func='%s'\n", 
+					thread->threadnum, thread->iostate, (int)(t - thread->checktime), thread->actions, thread->curfunc);
+#else
+			ast_cli(a->fd, "Thread %d: state=%d, update=%d, actions=%d\n", 
+					thread->threadnum, thread->iostate, (int)(t - thread->checktime), thread->actions);
+#endif
+			threadcount++;
+		}
+		AST_LIST_UNLOCK(&pool->idle_list);
+		ast_cli(a->fd, "Active Threads:\n");
+		AST_LIST_LOCK(&pool->active_list);
+		AST_LIST_TRAVERSE(&pool->active_list, thread, list) {
+			if (thread->type == THREADPOOL_THREAD_TYPE_DYNAMIC)
+				type = 'D';
+			else
+				type = 'P';
+#ifdef DEBUG_SCHED_MULTITHREAD
+			ast_cli(a->fd, "Thread %c%d: state=%d, update=%d, actions=%d, func='%s'\n", 
+					type, thread->threadnum, thread->iostate, (int)(t - thread->checktime), thread->actions, thread->curfunc);
+#else
+			ast_cli(a->fd, "Thread %c%d: state=%d, update=%d, actions=%d\n", 
+					type, thread->threadnum, thread->iostate, (int)(t - thread->checktime), thread->actions);
+#endif
+			threadcount++;
+		}
+		AST_LIST_UNLOCK(&pool->active_list);
+		ast_cli(a->fd, "Dynamic Threads:\n");
+		AST_LIST_LOCK(&pool->dynamic_list);
+		AST_LIST_TRAVERSE(&pool->dynamic_list, thread, list) {
+#ifdef DEBUG_SCHED_MULTITHREAD
+			ast_cli(a->fd, "Thread %d: state=%d, update=%d, actions=%d, func='%s'\n",
+					thread->threadnum, thread->iostate, (int)(t - thread->checktime), thread->actions, thread->curfunc);
+#else
+			ast_cli(a->fd, "Thread %d: state=%d, update=%d, actions=%d\n",
+					thread->threadnum, thread->iostate, (int)(t - thread->checktime), thread->actions);
+#endif
+			dynamiccount++;
+		}
+		AST_LIST_UNLOCK(&pool->dynamic_list);
+		ast_cli(a->fd, "%d of %d threads accounted for with %d dynamic threads\n\n\n", threadcount, pool->threadcount, dynamiccount);
+	}
+	return CLI_SUCCESS;
+}
+
+static struct ast_cli_entry threadpool_cli[] = {
+	AST_CLI_DEFINE(handle_cli_core_show_threadpools, "Shows all Threadpools and their thread status"),
+};
+
+void ast_threadpools_init(void)
+{
+	ast_cli_register_multiple(threadpool_cli, ARRAY_LEN(threadpool_cli));
+}

Propchange: team/murf/threadpool/main/threadpool.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/murf/threadpool/main/threadpool.c
------------------------------------------------------------------------------
    svn:keywords = Author Id Date Revision

Propchange: team/murf/threadpool/main/threadpool.c
------------------------------------------------------------------------------
    svn:mime-type = text/plain




More information about the asterisk-commits mailing list