diff options
author | smkelly <smkelly@FreeBSD.org> | 2003-06-26 09:50:52 +0000 |
---|---|---|
committer | smkelly <smkelly@FreeBSD.org> | 2003-06-26 09:50:52 +0000 |
commit | d45e58ad731761c5ee7051580c01c0a05c8d9322 (patch) | |
tree | 98951546927e0d8bb8a7c45b699a83ac3f8e84a9 /sys/kern/kern_clock.c | |
parent | 1cee3fa00127dc5a0eac1e6b6d9f489d1324437f (diff) | |
download | FreeBSD-src-d45e58ad731761c5ee7051580c01c0a05c8d9322.zip FreeBSD-src-d45e58ad731761c5ee7051580c01c0a05c8d9322.tar.gz |
- Add a software watchdog facility.
This commit has two pieces. One half is the watchdog kernel code which lives
primarily in hardclock() in sys/kern/kern_clock.c. The other half is a userland
daemon which, when run, will keep the watchdog from firing while the userland
is intact and functioning.
Approved by: jeff (mentor)
Diffstat (limited to 'sys/kern/kern_clock.c')
-rw-r--r-- | sys/kern/kern_clock.c | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/sys/kern/kern_clock.c b/sys/kern/kern_clock.c index 50a48b1..53729d2 100644 --- a/sys/kern/kern_clock.c +++ b/sys/kern/kern_clock.c @@ -42,6 +42,8 @@ __FBSDID("$FreeBSD$"); #include "opt_ntp.h" +#include "opt_ddb.h" +#include "opt_watchdog.h" #include <sys/param.h> #include <sys/systm.h> @@ -71,6 +73,10 @@ __FBSDID("$FreeBSD$"); #include <sys/gmon.h> #endif +#ifdef DDB +#include <ddb/ddb.h> +#endif + #ifdef DEVICE_POLLING extern void hardclock_device_poll(void); #endif /* DEVICE_POLLING */ @@ -84,6 +90,22 @@ long cp_time[CPUSTATES]; SYSCTL_OPAQUE(_kern, OID_AUTO, cp_time, CTLFLAG_RD, &cp_time, sizeof(cp_time), "LU", "CPU time statistics"); +#ifdef WATCHDOG +static int sysctl_watchdog_reset(SYSCTL_HANDLER_ARGS); +static void watchdog_fire(void); + +static int watchdog_enabled; +static unsigned int watchdog_ticks; +static int watchdog_timeout = 20; + +SYSCTL_NODE(_debug, OID_AUTO, watchdog, CTLFLAG_RW, 0, "System watchdog"); +SYSCTL_INT(_debug_watchdog, OID_AUTO, enabled, CTLFLAG_RW, &watchdog_enabled, + 0, "Enable the watchdog"); +SYSCTL_INT(_debug_watchdog, OID_AUTO, timeout, CTLFLAG_RW, &watchdog_timeout, + 0, "Timeout for watchdog checkins"); + +#endif /* WATCHDOG */ + /* * Clock handling routines. * @@ -228,6 +250,12 @@ hardclock(frame) */ if (need_softclock) swi_sched(softclock_ih, 0); + +#ifdef WATCHDOG + if (watchdog_enabled > 0 && + (int)(ticks - watchdog_ticks) >= (hz * watchdog_timeout)) + watchdog_fire(); +#endif /* WATCHDOG */ } /* @@ -481,3 +509,57 @@ sysctl_kern_clockrate(SYSCTL_HANDLER_ARGS) SYSCTL_PROC(_kern, KERN_CLOCKRATE, clockrate, CTLTYPE_STRUCT|CTLFLAG_RD, 0, 0, sysctl_kern_clockrate, "S,clockinfo", "Rate and period of various kernel clocks"); + +#ifdef WATCHDOG +/* + * Reset the watchdog timer to ticks, thus preventing the watchdog + * from firing for another watchdog timeout period. + */ +static int +sysctl_watchdog_reset(SYSCTL_HANDLER_ARGS) +{ + int ret; + + ret = 0; + watchdog_ticks = ticks; + return sysctl_handle_int(oidp, &ret, 0, req); +} + +SYSCTL_PROC(_debug_watchdog, OID_AUTO, reset, CTLFLAG_RW, 0, 0, + sysctl_watchdog_reset, "I", "Reset the watchdog"); + +/* + * Handle a watchdog timeout by dumping interrupt information and + * then either dropping to DDB or panicing. + */ +static void +watchdog_fire(void) +{ + int nintr; + u_int64_t inttotal; + u_long *curintr; + char *curname; + + curintr = intrcnt; + curname = intrnames; + inttotal = 0; + nintr = eintrcnt - intrcnt; + + printf("interrupt total\n"); + while (--nintr >= 0) { + if (*curintr) + printf("%-12s %20lu\n", curname, *curintr); + curname += strlen(curname) + 1; + inttotal += *curintr++; + } + printf("Total %20llu\n", inttotal); + +#ifdef DDB + db_print_backtrace(); + Debugger("watchdog timeout"); +#else /* !DDB */ + panic("watchdog timeout"); +#endif /* DDB */ +} + +#endif /* WATCHDOG */ |