PERFORCE change 101572 for review
John Baldwin
jhb at FreeBSD.org
Fri Jul 14 16:40:28 UTC 2006
http://perforce.freebsd.org/chv.cgi?CH=101572
Change 101572 by jhb at jhb_mutex on 2006/07/14 16:39:44
Use a mutex to protect the list of config_intr_hook's. In order
to handle the case where a driver might get an interrupt and ask
to remove its handler while the previous handler in the list is
running, fixup the next_entry handler if needed when a handler is
disestablished. To make that work, use an sx lock to ensure only
one thread can run the current list of hooks at a time.
Affected files ...
.. //depot/projects/smpng/sys/kern/subr_autoconf.c#7 edit
Differences ...
==== //depot/projects/smpng/sys/kern/subr_autoconf.c#7 (text+ko) ====
@@ -39,7 +39,10 @@
#include <sys/param.h>
#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
#include <sys/systm.h>
+#include <sys/sx.h>
/*
* Autoconfiguration subroutines.
@@ -50,26 +53,49 @@
*/
static TAILQ_HEAD(, intr_config_hook) intr_config_hook_list =
TAILQ_HEAD_INITIALIZER(intr_config_hook_list);
+static struct mtx intr_config_hook_lock;
+MTX_SYSINIT(intr_config_hook, &intr_config_hook_lock, "intr config", MTX_DEF);
+static struct sx intr_config_run_lock;
+SX_SYSINIT(intr_config_run, &intr_config_run_lock, "intr config run");
+/*
+ * The current location in the list when a thread is executing the current
+ * hooks. If this hook is removed we advance it to the next entry.
+ */
+static struct intr_config_hook *next_entry;
/* ARGSUSED */
static void run_interrupt_driven_config_hooks(void *dummy);
+
static void
run_interrupt_driven_config_hooks(dummy)
void *dummy;
{
- struct intr_config_hook *hook_entry, *next_entry;
+ struct intr_config_hook *hook_entry;
+
+ /*
+ * Because of the special care for next_entry, we can only allow one
+ * thread at a time to run through the list.
+ */
+ sx_xlock(&intr_config_run_lock);
+ mtx_lock(&intr_config_hook_lock);
for (hook_entry = TAILQ_FIRST(&intr_config_hook_list);
hook_entry != NULL;
hook_entry = next_entry) {
next_entry = TAILQ_NEXT(hook_entry, ich_links);
+ mtx_unlock(&intr_config_hook_lock);
(*hook_entry->ich_func)(hook_entry->ich_arg);
+ mtx_lock(&intr_config_hook_lock);
}
while (!TAILQ_EMPTY(&intr_config_hook_list)) {
- tsleep(&intr_config_hook_list, PCONFIG, "conifhk", 0);
+ msleep(&intr_config_hook_list, &intr_config_hook_lock, PCONFIG,
+ "conifhk", 0);
}
+ mtx_unlock(&intr_config_hook_lock);
+
+ sx_xunlock(&intr_config_run_lock);
}
SYSINIT(intr_config_hooks, SI_SUB_INT_CONFIG_HOOKS, SI_ORDER_FIRST,
run_interrupt_driven_config_hooks, NULL)
@@ -85,17 +111,18 @@
{
struct intr_config_hook *hook_entry;
- for (hook_entry = TAILQ_FIRST(&intr_config_hook_list);
- hook_entry != NULL;
- hook_entry = TAILQ_NEXT(hook_entry, ich_links))
+ mtx_lock(&intr_config_hook_lock);
+ TAILQ_FOREACH(hook_entry, &intr_config_hook_list, ich_links)
if (hook_entry == hook)
break;
if (hook_entry != NULL) {
+ mtx_unlock(&intr_config_hook_lock);
printf("config_intrhook_establish: establishing an "
"already established hook.\n");
return (1);
}
TAILQ_INSERT_TAIL(&intr_config_hook_list, hook, ich_links);
+ mtx_unlock(&intr_config_hook_lock);
if (cold == 0)
/* XXX Sufficient for modules loaded after initial config??? */
run_interrupt_driven_config_hooks(NULL);
@@ -108,16 +135,23 @@
{
struct intr_config_hook *hook_entry;
- for (hook_entry = TAILQ_FIRST(&intr_config_hook_list);
- hook_entry != NULL;
- hook_entry = TAILQ_NEXT(hook_entry, ich_links))
+ mtx_lock(&intr_config_hook_lock);
+ TAILQ_FOREACH(hook_entry, &intr_config_hook_list, ich_links)
if (hook_entry == hook)
break;
if (hook_entry == NULL)
panic("config_intrhook_disestablish: disestablishing an "
"unestablished hook");
+ /*
+ * If a thread is going to run this hook next, advance it's next
+ * pointer.
+ */
+ if (hook == next_entry)
+ next_entry = TAILQ_NEXT(next_entry, ich_links);
TAILQ_REMOVE(&intr_config_hook_list, hook, ich_links);
+
/* Wakeup anyone watching the list */
wakeup(&intr_config_hook_list);
+ mtx_unlock(&intr_config_hook_lock);
}
More information about the p4-projects
mailing list