PERFORCE change 82426 for review

John Baldwin jhb at FreeBSD.org
Mon Aug 22 21:40:20 GMT 2005


http://perforce.freebsd.org/chv.cgi?CH=82426

Change 82426 by jhb at jhb_slimer on 2005/08/22 21:39:57

	Use a linker set for the crash events so that it is easier to
	add new events.

Affected files ...

.. //depot/projects/smpng/sys/modules/crash/crash.c#15 edit

Differences ...

==== //depot/projects/smpng/sys/modules/crash/crash.c#15 (text+ko) ====

@@ -54,37 +54,25 @@
 #include <sys/sysctl.h>
 #include <sys/systm.h>
 
-#define	MAX_EVENT	21
+struct crash_event {
+	const char *ev_name;
+	void (*ev_handler)(void);
+};
+
+SET_DECLARE(crash_event_set, struct crash_event);
+
+#define	CRASH_EVENT(name, function)					\
+	static struct crash_event function ## _crash_event =		\
+	    { name, function };						\
+	DATA_SET(crash_event_set, function ## _crash_event)
+
+#define	MAX_EVENT	SET_COUNT(crash_event_set)
 
 static struct sx foo, bar, bar2;
 static struct cv event_cv;
 static struct mtx event_mtx, test_mtx, test1_mtx, test2_mtx;
 static struct proc *kthread;
 static int event;
-static const char *event_names[] = {
-	NULL,		/* 0 - no event */
-	"help",
-	"foo then bar",
-	"bar then foo",
-	"bar then foo then bar",
-	"Giant then foo then sleep",
-	"wakeup then foo then Giant",
-	"slock foo, upgrade, and release",
-	"xlock foo, downgrade, and release",
-	"xlock foo, upgrade",
-	"slock foo, downgrade",
-	"slock foo, upgrade, sunlock",
-	"xlock foo, downgrade, xunlock",
-	"re-init of test_mtx",
-	"assert that Giant is locked while it is unlocked",
-	"assert that foo is slocked while it is xlocked",
-	"lock test, slock foo, sunlock foo, unlock test",
-	"use test1 and test2 mutexes to test witness removal",
-	"try lock tests including recursion test",
-	"test witness_defineorder and witness_checkorder",
-	"blow the kernel stack on purpose",
-	"test deep stack backtraces",
-};
 
 static int	mod_event(struct module *module, int cmd, void *arg);
 static int	load(void *arg);
@@ -92,28 +80,242 @@
 static int	shutdown(void *arg);
 static void	crash_thread(void *arg);
 
-SYSCTL_NODE(_debug, OID_AUTO, crash, CTLFLAG_RD, 0, "crash tree");
+/* Events. */
+
+static void
+foo_then_bar(void)
+{
+	sx_slock(&foo);
+	sx_slock(&bar);
+	sx_sunlock(&foo);
+	sx_sunlock(&bar);
+}
+CRASH_EVENT("foo then bar", foo_then_bar);
+
+static void
+bar_then_foo(void)
+{
+	sx_slock(&bar);
+	sx_slock(&foo);
+	sx_sunlock(&foo);
+	sx_sunlock(&bar);
+}
+CRASH_EVENT("bar then foo", bar_then_foo);
+
+static void
+bar_then_foo_then_bar(void)
+{
+	sx_slock(&bar);
+	sx_slock(&foo);
+	sx_slock(&bar2);
+	sx_sunlock(&bar2);
+	sx_sunlock(&foo);
+	sx_sunlock(&bar);
+}
+CRASH_EVENT("bar then foo then bar", bar_then_foo_then_bar);
+
+static void
+Giant_then_foo_then_sleep(void)
+{
+	mtx_lock(&Giant);
+	sx_slock(&foo);
+}
+CRASH_EVENT("Giant then foo then sleep", Giant_then_foo_then_sleep);
 
-static int
-sysctl_debug_crash_test(SYSCTL_HANDLER_ARGS)
+static void
+wakeup_then_foo_then_Giant(void)
 {
-	int error, i = 0;
+	sx_sunlock(&foo);
+	mtx_unlock(&Giant);
+}
+CRASH_EVENT("wakeup then foo then Giant", wakeup_then_foo_then_Giant);
 
-	error = sysctl_handle_int(oidp, &i, sizeof(i), req);
-	if (error == 0 && req->newptr != NULL) {
-		if (i >= 1 && i <= MAX_EVENT) {
-			mtx_lock(&event_mtx);
-			KASSERT(event == 0, ("event %d was unhandled", event));
-			event = i;
-			cv_signal(&event_cv);
-			mtx_unlock(&event_mtx);
-		} else
-			error = EINVAL;
+static void
+upgrade_foo(void)
+{
+	sx_slock(&foo);
+	if (sx_try_upgrade(&foo) == 0) {
+		printf("crash: umm, upgrade failed?\n");
+		sx_sunlock(&foo);
 	}
-	return (error);
+	sx_xunlock(&foo);
+}
+CRASH_EVENT("slock foo, upgrade, and release", upgrade_foo);
+
+static void
+downgrade_foo(void)
+{
+	sx_xlock(&foo);
+	sx_downgrade(&foo);
+	sx_sunlock(&foo);
+}
+CRASH_EVENT("xlock foo, downgrade, and release", downgrade_foo);
+
+static void
+upgrade_excl_foo(void)
+{
+	sx_xlock(&foo);
+	sx_try_upgrade(&foo);
+}
+CRASH_EVENT("xlock foo, upgrade", upgrade_excl_foo);
+
+static void
+downgrade_shared_foo(void)
+{
+	sx_slock(&foo);
+	sx_downgrade(&foo);
+}
+CRASH_EVENT("slock foo, downgrade", downgrade_shared_foo);
+
+static void
+sunlock_upgraded_foo(void)
+{
+	sx_slock(&foo);
+	sx_try_upgrade(&foo);
+	sx_sunlock(&foo);
+}
+CRASH_EVENT("slock foo, upgrade, sunlock", sunlock_upgraded_foo);
+
+static void
+xunlock_downgraded_foo(void)
+{
+	sx_xlock(&foo);
+	sx_downgrade(&foo);
+	sx_xunlock(&foo);
+}
+CRASH_EVENT("xlock foo, downgrade, xunlock", xunlock_downgraded_foo);
+
+static void
+double_mtx_init(void)
+{
+	kdb_enter("about to init again");
+	mtx_init(&test_mtx, "test", NULL, MTX_DEF);
+	kdb_enter("if we haven't panic'd by now, ouch. :(");
+	mtx_destroy(&test_mtx);
+}
+CRASH_EVENT("re-init of test_mtx", double_mtx_init);
+
+static void
+test_mtx_assert(void)
+{
+	mtx_assert(&Giant, MA_OWNED);
+}
+CRASH_EVENT("assert that Giant is locked while it is unlocked",
+    test_mtx_assert);
+
+static void
+test_sx_assert_slocked(void)
+{
+	sx_xlock(&foo);
+	sx_assert(&foo, SX_SLOCKED);
+	sx_xunlock(&foo);
+}
+CRASH_EVENT("assert that foo is slocked while it is xlocked",
+    test_sx_assert_slocked);
+
+static void
+test_sx_and_mtx_order(void)
+{
+	mtx_lock(&test_mtx);
+	sx_slock(&foo);
+	sx_sunlock(&foo);
+	mtx_unlock(&test_mtx);
+}
+CRASH_EVENT("lock test, slock foo, sunlock foo, unlock test",
+    test_sx_and_mtx_order);
+
+static void
+test_witness_removal(void)
+{
+	bzero(&test1_mtx, sizeof(test1_mtx));
+	bzero(&test2_mtx, sizeof(test2_mtx));
+	mtx_init(&test1_mtx, "test1", NULL, MTX_DEF);
+	mtx_init(&test2_mtx, "test2", NULL, MTX_DEF);
+	kdb_enter("no order yet");
+	mtx_lock(&Giant);
+	mtx_lock(&test1_mtx);
+	mtx_lock(&test2_mtx);
+	mtx_unlock(&test2_mtx);
+	mtx_unlock(&test1_mtx);
+	mtx_unlock(&Giant);
+	kdb_enter("test1 and test2 should be ordered");
+	mtx_destroy(&test1_mtx);
+	kdb_enter("test1 should be gone, test2 should be after Giant");
+	mtx_destroy(&test2_mtx);
+	kdb_enter("test1 and test2 should be gone");
+}
+CRASH_EVENT("use test1 and test2 mutexes to test witness removal",
+    test_witness_removal);
+
+static void
+test_try_locks(void)
+{
+	int status;
+
+	bzero(&test1_mtx, sizeof(test1_mtx));
+	bzero(&test2_mtx, sizeof(test2_mtx));
+	mtx_init(&test1_mtx, "test1", NULL, MTX_DEF);
+	mtx_init(&test2_mtx, "test2", NULL, MTX_DEF | MTX_RECURSE);
+#define TRYLOCK_TEST(lock, descr) do {					\
+	status = mtx_trylock((lock));					\
+	printf("Try lock of " descr ": %d;  recurse = %d\n",		\
+	    status, (lock)->mtx_recurse);				\
+	if (status)							\
+		mtx_unlock((lock));					\
+} while(0)
+	TRYLOCK_TEST(&test1_mtx, "unlocked test1");
+	mtx_lock(&test1_mtx);
+	TRYLOCK_TEST(&test1_mtx, "non-recursive locked test1");
+	mtx_unlock(&test1_mtx);
+	TRYLOCK_TEST(&test2_mtx, "unlocked test2");
+	mtx_lock(&test2_mtx);
+	TRYLOCK_TEST(&test2_mtx, "recursive locked test2");
+	mtx_unlock(&test2_mtx);
+#undef TRYLOCK_TEST
+	mtx_destroy(&test1_mtx);
+	mtx_destroy(&test2_mtx);
+}
+CRASH_EVENT("try lock tests including recursion test", test_try_locks);
+
+#if 0
+static void
+test_witness_order_funcs(void)
+{
+	int status;
+
+	bzero(&test1_mtx, sizeof(test1_mtx));
+	bzero(&test2_mtx, sizeof(test2_mtx));
+	mtx_init(&test1_mtx, "test1", NULL, MTX_DEF);
+	mtx_init(&test2_mtx, "test2", NULL, MTX_DEF);
+	kdb_enter("no order yet");
+	status = WITNESS_DEFINEORDER(&test1_mtx, &test2_mtx);
+	printf("Status of test1 -> test2 set order should be 0: %d\n", status);
+	kdb_enter("order should be test1 then test2");
+	printf("Check order of test1 -> test2 should succeed.\n");
+	mtx_lock(&test1_mtx);
+	witness_check_mutex(&test2_mtx);
+	mtx_unlock(&test1_mtx);
+	status = WITNESS_DEFINEORDER(&test2_mtx, &test1_mtx);
+	printf("Status of test2 -> test1 set order should be EDOOFUS: %d\n",
+	    status);
+	printf("Clearing test order.\n");
+	mtx_destroy(&test1_mtx);
+	mtx_destroy(&test2_mtx);
+	mtx_init(&test1_mtx, "test1", NULL, MTX_DEF);
+	mtx_init(&test2_mtx, "test2", NULL, MTX_DEF);
+	status = WITNESS_DEFINEORDER(&test1_mtx, &test2_mtx);
+	printf("Status of test1 -> test2 set order should be 0: %d\n", status);
+	printf("Should get a reversal:\n");
+	mtx_lock(&test2_mtx);
+	mtx_lock(&test1_mtx);
+	mtx_unlock(&test1_mtx);
+	mtx_unlock(&test2_mtx);
+	mtx_destroy(&test1_mtx);
+	mtx_destroy(&test2_mtx);
 }
-SYSCTL_PROC(_debug_crash, OID_AUTO, test, CTLTYPE_INT | CTLFLAG_RW, 0, 0,
-    sysctl_debug_crash_test, "I", "");
+CRASH_EVENT("test witness_defineorder and witness_checkorder",
+    test_witness_order_funcs);
+#endif
 
 static int
 blow_stack(void)
@@ -125,6 +327,13 @@
 }
 
 static void
+test_double_fault(void)
+{
+	(void)blow_stack();
+}
+CRASH_EVENT("blow the kernel stack on purpose", test_double_fault);
+
+static void
 recurse_deep(int depth)
 {
 
@@ -136,194 +345,84 @@
 }
 
 static void
+test_deep_stack_trace(void)
+{
+	recurse_deep(0);
+}
+CRASH_EVENT("test deep stack backtraces", test_deep_stack_trace);
+
+/* Help event should be last so that it is always event 1. */
+
+static void
+help(void)
+{
+	struct crash_event **ev;
+
+	SET_FOREACH(ev, crash_event_set) {
+		/* Skip null event 0. */
+		if ((*ev)->ev_name == NULL)
+			continue;
+		printf("%4d  %s\n", ev - SET_BEGIN(crash_event_set),
+		    (*ev)->ev_name);
+	}
+}
+CRASH_EVENT("help", help);
+
+/* Null event 0. */
+
+static void
+nop(void)
+{
+}
+CRASH_EVENT(NULL, nop);
+
+SYSCTL_NODE(_debug, OID_AUTO, crash, CTLFLAG_RD, 0, "crash tree");
+
+static int
+sysctl_debug_crash_test(SYSCTL_HANDLER_ARGS)
+{
+	int error, i = 0;
+
+	error = sysctl_handle_int(oidp, &i, sizeof(i), req);
+	if (error == 0 && req->newptr != NULL) {
+		if (i >= 1 && i < MAX_EVENT) {
+			mtx_lock(&event_mtx);
+			KASSERT(event == 0, ("event %d was unhandled", event));
+			event = i;
+			cv_signal(&event_cv);
+			mtx_unlock(&event_mtx);
+		} else
+			error = EINVAL;
+	}
+	return (error);
+}
+SYSCTL_PROC(_debug_crash, OID_AUTO, test, CTLTYPE_INT | CTLFLAG_RW, 0, 0,
+    sysctl_debug_crash_test, "I", "");
+
+static void
 crash_thread(void *arg)
 {
-	int ev, status;
+	struct crash_event *evp;
+	int ev;
 
+	help();
 	while (1) {
 		mtx_lock(&event_mtx);
 		while ((ev = event) == 0)
 			cv_wait(&event_cv, &event_mtx);
 		event = 0;
 		mtx_unlock(&event_mtx);
-		if (ev >= 1 && ev <= MAX_EVENT && event_names[ev] != NULL)
-			printf("crash: %s\n", event_names[ev]);
-		switch (ev) {
-		case -1:
+		if (ev == -1) {
 			kthread_exit(0);
 			break;
-		case 0:
-			break;
-		case 1:
-			for (ev = 1; ev <= MAX_EVENT; ev++)
-				if (event_names[ev] != NULL)
-					printf("%4d  %s\n", ev,
-					    event_names[ev]);
-			break;
-		case 2:
-			sx_slock(&foo);
-			sx_slock(&bar);
-			sx_sunlock(&foo);
-			sx_sunlock(&bar);
-			break;
-		case 3:
-			sx_slock(&bar);
-			sx_slock(&foo);
-			sx_sunlock(&foo);
-			sx_sunlock(&bar);
-			break;
-		case 4:
-			sx_slock(&bar);
-			sx_slock(&foo);
-			sx_slock(&bar2);
-			sx_sunlock(&bar2);
-			sx_sunlock(&foo);
-			sx_sunlock(&bar);
-			break;
-		case 5:
-			mtx_lock(&Giant);
-			sx_slock(&foo);
-			break;
-		case 6:
-			sx_sunlock(&foo);
-			mtx_unlock(&Giant);
-			break;
-		case 7:
-			sx_slock(&foo);
-			if (sx_try_upgrade(&foo) == 0) {
-				printf("crash: umm, upgrade failed?\n");
-				sx_sunlock(&foo);
-			}
-			sx_xunlock(&foo);
-			break;
-		case 8:
-			sx_xlock(&foo);
-			sx_downgrade(&foo);
-			sx_sunlock(&foo);
-			break;
-		case 9:
-			sx_xlock(&foo);
-			sx_try_upgrade(&foo);
-			break;
-		case 10:
-			sx_slock(&foo);
-			sx_downgrade(&foo);
-			break;
-		case 11:
-			sx_slock(&foo);
-			sx_try_upgrade(&foo);
-			sx_sunlock(&foo);
-			break;
-		case 12:
-			sx_xlock(&foo);
-			sx_downgrade(&foo);
-			sx_xunlock(&foo);
-			break;
-		case 13:
-			kdb_enter("about to init again");
-			mtx_init(&test_mtx, "test", NULL, MTX_DEF);
-			kdb_enter("if we haven't panic'd by now, ouch. :(");
-			mtx_destroy(&test_mtx);
-			break;
-		case 14:
-			mtx_assert(&Giant, MA_OWNED);
-			break;
-		case 15:
-			sx_xlock(&foo);
-			sx_assert(&foo, SX_SLOCKED);
-			sx_xunlock(&foo);
-			break;
-		case 16:
-			mtx_lock(&test_mtx);
-			sx_slock(&foo);
-			sx_sunlock(&foo);
-			mtx_unlock(&test_mtx);
-			break;
-		case 17:
-			bzero(&test1_mtx, sizeof(test1_mtx));
-			bzero(&test2_mtx, sizeof(test2_mtx));
-			mtx_init(&test1_mtx, "test1", NULL, MTX_DEF);
-			mtx_init(&test2_mtx, "test2", NULL, MTX_DEF);
-			kdb_enter("no order yet");
-			mtx_lock(&Giant);
-			mtx_lock(&test1_mtx);
-			mtx_lock(&test2_mtx);
-			mtx_unlock(&test2_mtx);
-			mtx_unlock(&test1_mtx);
-			mtx_unlock(&Giant);
-			kdb_enter("test1 and test2 should be ordered");
-			mtx_destroy(&test1_mtx);
-			kdb_enter("test1 should be gone, test2 should be after Giant");
-			mtx_destroy(&test2_mtx);
-			kdb_enter("test1 and test2 should be gone");
-			break;
-		case 18:
-			bzero(&test1_mtx, sizeof(test1_mtx));
-			bzero(&test2_mtx, sizeof(test2_mtx));
-			mtx_init(&test1_mtx, "test1", NULL, MTX_DEF);
-			mtx_init(&test2_mtx, "test2", NULL, MTX_DEF |
-			    MTX_RECURSE);
-#define TRYLOCK_TEST(lock, descr) do {					\
-	status = mtx_trylock((lock));					\
-	printf("Try lock of " descr ": %d;  recurse = %d\n",		\
-	    status, (lock)->mtx_recurse);				\
-	if (status)							\
-		mtx_unlock((lock));					\
-} while(0)
-			TRYLOCK_TEST(&test1_mtx, "unlocked test1");
-			mtx_lock(&test1_mtx);
-			TRYLOCK_TEST(&test1_mtx, "non-recursive locked test1");
-			mtx_unlock(&test1_mtx);
-			TRYLOCK_TEST(&test2_mtx, "unlocked test2");
-			mtx_lock(&test2_mtx);
-			TRYLOCK_TEST(&test2_mtx, "recursive locked test2");
-			mtx_unlock(&test2_mtx);
-#undef TRYLOCK_TEST
-			mtx_destroy(&test1_mtx);
-			mtx_destroy(&test2_mtx);
-			break;
-		case 19:
-			bzero(&test1_mtx, sizeof(test1_mtx));
-			bzero(&test2_mtx, sizeof(test2_mtx));
-			mtx_init(&test1_mtx, "test1", NULL, MTX_DEF);
-			mtx_init(&test2_mtx, "test2", NULL, MTX_DEF);
-			kdb_enter("no order yet");
-			status = WITNESS_DEFINEORDER(&test1_mtx, &test2_mtx);
-			printf("Status of test1 -> test2 set order should be 0: %d\n",
-			    status);
-			kdb_enter("order should be test1 then test2");
-			printf("Check order of test1 -> test2 should succeed.\n");
-			mtx_lock(&test1_mtx);
-			witness_check_mutex(&test2_mtx);
-			mtx_unlock(&test1_mtx);
-			status = WITNESS_DEFINEORDER(&test2_mtx, &test1_mtx);
-			printf("Status of test2 -> test1 set order should be EDOOFUS: %d\n",
-			    status);
-			printf("Clearing test order.\n");
-			mtx_destroy(&test1_mtx);
-			mtx_destroy(&test2_mtx);
-			mtx_init(&test1_mtx, "test1", NULL, MTX_DEF);
-			mtx_init(&test2_mtx, "test2", NULL, MTX_DEF);
-			status = WITNESS_DEFINEORDER(&test1_mtx, &test2_mtx);
-			printf("Status of test1 -> test2 set order should be 0: %d\n",
-			    status);
-			printf("Should get a reversal:\n");
-			mtx_lock(&test2_mtx);
-			mtx_lock(&test1_mtx);
-			mtx_unlock(&test1_mtx);
-			mtx_unlock(&test2_mtx);
-			mtx_destroy(&test1_mtx);
-			mtx_destroy(&test2_mtx);
-			break;
-		case 20:
-			(void)blow_stack();
-			break;
-		case 21:
-			recurse_deep(0);
-			break;
-		default:
-			panic("event %d is bogus\n", event);
+		}
+		if (ev < 0 || ev >= MAX_EVENT) {
+			printf("crash: event %d is not defined!\n", event);
+			continue;
 		}
+		evp = SET_ITEM(crash_event_set, ev);
+		printf("crash: %s\n", evp->ev_name);
+		evp->ev_handler();
 	}
 }
 


More information about the p4-projects mailing list