summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/kern/kern_intr.c37
-rw-r--r--sys/sys/interrupt.h1
2 files changed, 35 insertions, 3 deletions
diff --git a/sys/kern/kern_intr.c b/sys/kern/kern_intr.c
index 1cd558e..1c37284 100644
--- a/sys/kern/kern_intr.c
+++ b/sys/kern/kern_intr.c
@@ -301,11 +301,29 @@ ithread_remove_handler(void *cookie)
ih->ih_name, ithread->it_name);
ok:
#endif
- TAILQ_REMOVE(&ithread->it_handlers, handler, ih_next);
- ithread_update(ithread);
+ /*
+ * If the interrupt thread is already running, then just mark this
+ * handler as being dead and let the ithread do the actual removal.
+ */
+ mtx_lock_spin(&sched_lock);
+ if (ithread->it_proc->p_stat != SWAIT) {
+ handler->ih_flags |= IH_DEAD;
+
+ /*
+ * Ensure that the thread will process the handler list
+ * again and remove this handler if it has already passed
+ * it on the list.
+ */
+ ithread->it_need = 1;
+ } else {
+ TAILQ_REMOVE(&ithread->it_handlers, handler, ih_next);
+ ithread_update(ithread);
+ }
+ mtx_unlock_spin(&sched_lock);
mtx_unlock_spin(&ithread_list_lock);
- free(handler, M_ITHREAD);
+ if ((handler->ih_flags & IH_DEAD) == 0)
+ free(handler, M_ITHREAD);
return (0);
}
@@ -468,6 +486,7 @@ ithread_loop(void *arg)
* another pass.
*/
atomic_store_rel_int(&ithd->it_need, 0);
+restart:
TAILQ_FOREACH(ih, &ithd->it_handlers, ih_next) {
if (ithd->it_flags & IT_SOFT && !ih->ih_need)
continue;
@@ -480,6 +499,18 @@ ithread_loop(void *arg)
if ((ih->ih_flags & IH_MPSAFE) == 0)
mtx_lock(&Giant);
+ if ((ih->ih_flags & IH_DEAD) != 0) {
+ mtx_lock_spin(&ithread_list_lock);
+ TAILQ_REMOVE(&ithd->it_handlers, ih,
+ ih_next);
+ ithread_update(ithd);
+ mtx_unlock_spin(&ithread_list_lock);
+ if (!mtx_owned(&Giant))
+ mtx_lock(&Giant);
+ free(ih, M_ITHREAD);
+ mtx_unlock(&Giant);
+ goto restart;
+ }
ih->ih_handler(ih->ih_argument);
if ((ih->ih_flags & IH_MPSAFE) == 0)
mtx_unlock(&Giant);
diff --git a/sys/sys/interrupt.h b/sys/sys/interrupt.h
index 1bc48d6..9c44d81 100644
--- a/sys/sys/interrupt.h
+++ b/sys/sys/interrupt.h
@@ -50,6 +50,7 @@ struct intrhand {
#define IH_FAST 0x00000001 /* Fast interrupt. */
#define IH_EXCLUSIVE 0x00000002 /* Exclusive interrupt. */
#define IH_ENTROPY 0x00000004 /* Device is a good entropy source. */
+#define IH_DEAD 0x00000008 /* Handler should be removed. */
#define IH_MPSAFE 0x80000000 /* Handler does not need Giant. */
/*
OpenPOWER on IntegriCloud