diff options
author | jhb <jhb@FreeBSD.org> | 2006-07-19 18:53:56 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2006-07-19 18:53:56 +0000 |
commit | 70424c0f306a3e1040c5ff78f5d0b2275689cbb9 (patch) | |
tree | e67c5551e33b89782d526060e8751242b595a51c /sys/kern/subr_autoconf.c | |
parent | 7863d70730bd1f7afe32c78e631b91fc0c2dd01e (diff) | |
download | FreeBSD-src-70424c0f306a3e1040c5ff78f5d0b2275689cbb9.zip FreeBSD-src-70424c0f306a3e1040c5ff78f5d0b2275689cbb9.tar.gz |
Add a mutex to protect the list of interrupt config hooks. We do assume
that the only remove hook operation that can occur while processing the
hooks is to remove the currently executing hook. This should be safe as
the existing code has assumed this already for a long time now.
Reviewed by: scottl
MFC after: 1 week
Diffstat (limited to 'sys/kern/subr_autoconf.c')
-rw-r--r-- | sys/kern/subr_autoconf.c | 32 |
1 files changed, 21 insertions, 11 deletions
diff --git a/sys/kern/subr_autoconf.c b/sys/kern/subr_autoconf.c index d40f1e4..067e155 100644 --- a/sys/kern/subr_autoconf.c +++ b/sys/kern/subr_autoconf.c @@ -39,6 +39,8 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/kernel.h> +#include <sys/lock.h> +#include <sys/mutex.h> #include <sys/systm.h> /* @@ -50,26 +52,32 @@ __FBSDID("$FreeBSD$"); */ 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); /* 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; - for (hook_entry = TAILQ_FIRST(&intr_config_hook_list); - hook_entry != NULL; - hook_entry = next_entry) { + mtx_lock(&intr_config_hook_lock); + TAILQ_FOREACH_SAFE(hook_entry, &intr_config_hook_list, ich_links, + 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); } SYSINIT(intr_config_hooks, SI_SUB_INT_CONFIG_HOOKS, SI_ORDER_FIRST, run_interrupt_driven_config_hooks, NULL) @@ -85,17 +93,18 @@ config_intrhook_establish(hook) { 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,9 +117,8 @@ config_intrhook_disestablish(hook) { 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) @@ -118,6 +126,8 @@ config_intrhook_disestablish(hook) "unestablished hook"); 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); } |