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