aboutsummaryrefslogtreecommitdiff
path: root/sys/kern/kern_clock.c
diff options
context:
space:
mode:
authorSean Kelly <smkelly@FreeBSD.org>2003-06-26 09:50:52 +0000
committerSean Kelly <smkelly@FreeBSD.org>2003-06-26 09:50:52 +0000
commit370c3cb57cb5163d6847a6824b2720554e33754a (patch)
tree98951546927e0d8bb8a7c45b699a83ac3f8e84a9 /sys/kern/kern_clock.c
parentb1d6647755b888699300101f04f8157596292f4c (diff)
downloadsrc-370c3cb57cb5163d6847a6824b2720554e33754a.tar.gz
src-370c3cb57cb5163d6847a6824b2720554e33754a.zip
Notes
Diffstat (limited to 'sys/kern/kern_clock.c')
-rw-r--r--sys/kern/kern_clock.c82
1 files changed, 82 insertions, 0 deletions
diff --git a/sys/kern/kern_clock.c b/sys/kern/kern_clock.c
index 50a48b10084b..53729d2040c3 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 */