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