[asterisk-commits] russell: branch russell/debug_threads r77843 - /team/russell/debug_threads/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Jul 31 15:12:27 CDT 2007


Author: russell
Date: Tue Jul 31 15:12:26 2007
New Revision: 77843

URL: http://svn.digium.com/view/asterisk?view=rev&rev=77843
Log:
Introduce a "core show locks" CLI command.  This CLI command will list which
locks each active thread on the system currently holds.

Modified:
    team/russell/debug_threads/utils.c

Modified: team/russell/debug_threads/utils.c
URL: http://svn.digium.com/view/asterisk/team/russell/debug_threads/utils.c?view=diff&rev=77843&r1=77842&r2=77843
==============================================================================
--- team/russell/debug_threads/utils.c (original)
+++ team/russell/debug_threads/utils.c Tue Jul 31 15:12:26 2007
@@ -47,6 +47,8 @@
 #include "asterisk/md5.h"
 #include "asterisk/options.h"
 #include "asterisk/compat.h"
+#include "asterisk/linkedlists.h"
+#include "asterisk/cli.h"
 
 #define AST_API_MODULE		/* ensure that inlinable API functions will be built in this module if required */
 #include "asterisk/strings.h"
@@ -472,12 +474,6 @@
 	return inet_ntop(AF_INET, &ia, buf, bufsiz);
 }
 
-int ast_utils_init(void)
-{
-	base64_init();
-	return 0;
-}
-
 #ifndef __linux__
 #undef pthread_create /* For ast_pthread_create function only */
 #endif /* !__linux__ */
@@ -499,9 +495,17 @@
 /*! \brief A reasonable maximum number of locks a thread would be holding ... */
 #define AST_MAX_LOCKS 16
 
+/* Allow direct use of pthread_mutex_t */
+#undef pthread_mutex_t
+#undef pthread_mutex_lock
+#undef pthread_mutex_unlock
+#undef pthread_mutex_init
+#undef pthread_mutex_destroy
+
 /*! \brief Keep track of which locks a thread holds */
 struct thr_lock_info {
 	pthread_t thread_id;
+	const char *thread_name;
 	struct {
 		const char *file;
 		int line_num;
@@ -511,12 +515,25 @@
 		int times_locked;
 	} locks[AST_MAX_LOCKS];
 	unsigned int num_locks;
+	/* Protects the contents of the locks member 
+	 * Intentionally not ast_mutex_t */
+	pthread_mutex_t lock;
+	AST_LIST_ENTRY(thr_lock_info) entry;
 };
 
+AST_RWLOCK_DEFINE_STATIC(lock_infos_rwlock);
+static AST_LIST_HEAD_NOLOCK_STATIC(lock_infos, thr_lock_info);
+
 static void lock_info_destroy(void *data)
 {
 	struct thr_lock_info *lock_info = data;
 
+	pthread_rwlock_wrlock(&lock_infos_rwlock);
+	AST_LIST_REMOVE(&lock_infos, lock_info, entry);
+	pthread_rwlock_unlock(&lock_infos_rwlock);
+
+	pthread_mutex_destroy(&lock_info->lock);
+	free((void *) lock_info->thread_name);
 	free(lock_info);
 }
 
@@ -530,10 +547,13 @@
 
 	if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
 		return;
+
+	pthread_mutex_lock(&lock_info->lock);
 
 	for (i = 0; i < lock_info->num_locks; i++) {
 		if (lock_info->locks[i].lock_addr == lock_addr) {
 			lock_info->locks[i].times_locked++;
+			pthread_mutex_unlock(&lock_info->lock);
 			return;
 		}
 	}
@@ -542,6 +562,7 @@
 		/* Can't use ast_log here, because it will cause infinite recursion */
 		fprintf(stderr, "XXX ERROR XXX A thread holds more locks than '%d'."
 			"  Increase AST_MAX_LOCKS!\n", AST_MAX_LOCKS);
+		pthread_mutex_unlock(&lock_info->lock);
 		return;
 	}
 	
@@ -552,6 +573,8 @@
 	lock_info->locks[i].lock_addr = lock_addr;
 	lock_info->locks[i].times_locked = 1;
 	lock_info->num_locks++;
+
+	pthread_mutex_unlock(&lock_info->lock);
 }
 
 void ast_remove_lock_info(void *lock_addr)
@@ -561,17 +584,23 @@
 
 	if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
 		return;
+
+	pthread_mutex_lock(&lock_info->lock);
 
 	for (i = lock_info->num_locks - 1; i >= 0; i--) {
 		if (lock_info->locks[i].lock_addr == lock_addr)
 			break;
 	}
 
-	if (i == -1) /* Lock not found :( */
+	if (i == -1) {
+		/* Lock not found :( */
+		pthread_mutex_unlock(&lock_info->lock);
 		return;
+	}
 
 	if (lock_info->locks[i].times_locked > 1) {
 		lock_info->locks[i].times_locked--;
+		pthread_mutex_unlock(&lock_info->lock);
 		return;
 	}
 
@@ -582,7 +611,56 @@
 	}
 
 	lock_info->num_locks--;
-}
+
+	pthread_mutex_unlock(&lock_info->lock);
+}
+
+static int handle_show_locks(int fd, int argc, char *argv[])
+{
+	struct thr_lock_info *lock_info;
+
+	ast_cli(fd, "\n" 
+	            "=======================================================================\n"
+	            "=== Currently Held Locks ==============================================\n"
+	            "=======================================================================\n"
+	            "===\n"
+				"=== <file> <line num> <function> <lock name> <lock addr> (times locked)\n"
+				"===\n");
+
+	pthread_rwlock_rdlock(&lock_infos_rwlock);
+	AST_LIST_TRAVERSE(&lock_infos, lock_info, entry) {
+		int i;
+		ast_cli(fd, "=== Thread ID: %d (%s)\n", (int) lock_info->thread_id,
+			lock_info->thread_name);
+		pthread_mutex_lock(&lock_info->lock);
+		for (i = 0; i < lock_info->num_locks; i++) {
+			ast_cli(fd, "=== ---> Lock #%d: %s %d %s %s %p (%d)\n", i,
+				lock_info->locks[i].file, lock_info->locks[i].line_num,
+				lock_info->locks[i].func, lock_info->locks[i].lock_name,
+				lock_info->locks[i].lock_addr, 
+				lock_info->locks[i].times_locked);
+		}
+		pthread_mutex_unlock(&lock_info->lock);
+		ast_cli(fd, "=== -------------------------------------------------------------------\n"
+		            "===\n");
+	}
+	pthread_rwlock_unlock(&lock_infos_rwlock);
+
+	ast_cli(fd, "=======================================================================\n"
+	            "\n");
+
+	return 0;
+}
+
+static char show_locks_help[] =
+"Usage: core show locks\n"
+"       This command is for lock debugging.  It prints out which locks\n"
+"are owned by each active thread.\n";
+
+static struct ast_cli_entry utils_cli[] = {
+	{ { "core", "show", "locks", NULL }, handle_show_locks,
+	  "Show which locks are locked by which thread", show_locks_help },
+};
 
 #endif /* DEBUG_THREADS */
 
@@ -613,6 +691,12 @@
 		return NULL;
 
 	lock_info->thread_id = pthread_self();
+	lock_info->thread_name = strdup(a.name);
+	pthread_mutex_init(&lock_info->lock, NULL);
+
+	pthread_rwlock_wrlock(&lock_infos_rwlock); /* Intentionally not the wrapper */
+	AST_LIST_INSERT_TAIL(&lock_infos, lock_info, entry);
+	pthread_rwlock_unlock(&lock_infos_rwlock); /* Intentionally not the wrapper */
 
 #endif /* DEBUG_THREADS */
 
@@ -1083,3 +1167,14 @@
         ast_mutex_unlock(&fetchadd_m);
         return ret;
 }
+
+int ast_utils_init(void)
+{
+	base64_init();
+#ifdef DEBUG_THREADS
+	ast_cli_register_multiple(utils_cli, sizeof(utils_cli) / sizeof(utils_cli[0]));
+#endif
+	return 0;
+}
+
+




More information about the asterisk-commits mailing list