summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Watson <rwatson@FreeBSD.org>2008-07-27 23:28:29 +0000
committerRobert Watson <rwatson@FreeBSD.org>2008-07-27 23:28:29 +0000
commit3f981b77fa43a0eca4a2113444b788d578be46bd (patch)
treeea54ef6e227f854e786d46fa18e54c7b4d1a016b
parent14096966161d515cd5dadc9ec9aa09cf61bffcbc (diff)
Notes
-rw-r--r--sys/kern/subr_autoconf.c68
1 files changed, 66 insertions, 2 deletions
diff --git a/sys/kern/subr_autoconf.c b/sys/kern/subr_autoconf.c
index ef70f04237fb..75a97b23254f 100644
--- a/sys/kern/subr_autoconf.c
+++ b/sys/kern/subr_autoconf.c
@@ -37,8 +37,11 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include "opt_ddb.h"
+
#include <sys/param.h>
#include <sys/kernel.h>
+#include <sys/linker.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/systm.h>
@@ -58,11 +61,41 @@ MTX_SYSINIT(intr_config_hook, &intr_config_hook_lock, "intr config", MTX_DEF);
/* ARGSUSED */
static void run_interrupt_driven_config_hooks(void *dummy);
+/*
+ * If we wait too long for an interrupt-driven config hook to return, print
+ * a diagnostic.
+ */
+#define WARNING_INTERVAL_SECS 60
+static void
+run_interrupt_driven_config_hooks_warning(int warned)
+{
+ struct intr_config_hook *hook_entry;
+ char namebuf[64];
+ long offset;
+
+ if (warned < 6) {
+ printf("run_interrupt_driven_hooks: still waiting after %d "
+ "seconds for", warned * WARNING_INTERVAL_SECS);
+ TAILQ_FOREACH(hook_entry, &intr_config_hook_list, ich_links) {
+ if (linker_search_symbol_name(
+ (caddr_t)hook_entry->ich_func, namebuf,
+ sizeof(namebuf), &offset) == 0)
+ printf(" %s", namebuf);
+ else
+ printf(" %p", hook_entry->ich_func);
+ }
+ printf("\n");
+ }
+ KASSERT(warned < 6,
+ ("run_interrupt_driven_config_hooks: waited too long"));
+}
+
static void
run_interrupt_driven_config_hooks(dummy)
void *dummy;
{
struct intr_config_hook *hook_entry, *next_entry;
+ int warned;
mtx_lock(&intr_config_hook_lock);
TAILQ_FOREACH_SAFE(hook_entry, &intr_config_hook_list, ich_links,
@@ -72,9 +105,16 @@ run_interrupt_driven_config_hooks(dummy)
mtx_lock(&intr_config_hook_lock);
}
+ warned = 0;
while (!TAILQ_EMPTY(&intr_config_hook_list)) {
- msleep(&intr_config_hook_list, &intr_config_hook_lock, PCONFIG,
- "conifhk", 0);
+ if (msleep(&intr_config_hook_list, &intr_config_hook_lock,
+ PCONFIG, "conifhk", WARNING_INTERVAL_SECS * hz) ==
+ EWOULDBLOCK) {
+ mtx_unlock(&intr_config_hook_lock);
+ warned++;
+ run_interrupt_driven_config_hooks_warning(warned);
+ mtx_lock(&intr_config_hook_lock);
+ }
}
mtx_unlock(&intr_config_hook_lock);
}
@@ -130,3 +170,27 @@ config_intrhook_disestablish(hook)
wakeup(&intr_config_hook_list);
mtx_unlock(&intr_config_hook_lock);
}
+
+#ifdef DDB
+#include <ddb/ddb.h>
+
+DB_SHOW_COMMAND(conifhk, db_show_conifhk)
+{
+ struct intr_config_hook *hook_entry;
+ char namebuf[64];
+ long offset;
+
+ TAILQ_FOREACH(hook_entry, &intr_config_hook_list, ich_links) {
+ if (linker_ddb_search_symbol_name(
+ (caddr_t)hook_entry->ich_func, namebuf, sizeof(namebuf),
+ &offset) == 0) {
+ db_printf("hook: %p at %s+%#lx arg: %p\n",
+ hook_entry->ich_func, namebuf, offset,
+ hook_entry->ich_arg);
+ } else {
+ db_printf("hook: %p at ??+?? arg %p\n",
+ hook_entry->ich_func, hook_entry->ich_arg);
+ }
+ }
+}
+#endif /* DDB */