From owner-p4-projects@FreeBSD.ORG Mon Aug 22 21:40:20 2005 Return-Path: X-Original-To: p4-projects@freebsd.org Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id A76CB16A439; Mon, 22 Aug 2005 21:40:19 +0000 (GMT) X-Original-To: perforce@freebsd.org Delivered-To: perforce@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 761A716A435 for ; Mon, 22 Aug 2005 21:40:19 +0000 (GMT) (envelope-from jhb@freebsd.org) Received: from repoman.freebsd.org (repoman.freebsd.org [216.136.204.115]) by mx1.FreeBSD.org (Postfix) with ESMTP id BF3E143D77 for ; Mon, 22 Aug 2005 21:40:14 +0000 (GMT) (envelope-from jhb@freebsd.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.13.1/8.13.1) with ESMTP id j7MLeE0s073591 for ; Mon, 22 Aug 2005 21:40:14 GMT (envelope-from jhb@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.13.1/8.13.1/Submit) id j7MLeEGk073588 for perforce@freebsd.org; Mon, 22 Aug 2005 21:40:14 GMT (envelope-from jhb@freebsd.org) Date: Mon, 22 Aug 2005 21:40:14 GMT Message-Id: <200508222140.j7MLeEGk073588@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to jhb@freebsd.org using -f From: John Baldwin To: Perforce Change Reviews Cc: Subject: PERFORCE change 82426 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 22 Aug 2005 21:40:20 -0000 http://perforce.freebsd.org/chv.cgi?CH=82426 Change 82426 by jhb@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 #include -#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(); } }