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
This commit is contained in:
John Baldwin 2006-07-19 18:53:56 +00:00
parent 9c2dc11465
commit 9079458ad2
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=160509

View File

@ -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);
}