summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkan <kan@FreeBSD.org>2012-08-06 16:37:43 +0000
committerkan <kan@FreeBSD.org>2012-08-06 16:37:43 +0000
commit387a0565b369c91140724c97b0b9b2d7cfcba741 (patch)
tree4e8debfb47c31d83a46e0a1bbdf9c5ab8557cb9e
parenteed7c1d3a532f42854b50b30bef7bfe6bac1c302 (diff)
downloadFreeBSD-src-387a0565b369c91140724c97b0b9b2d7cfcba741.zip
FreeBSD-src-387a0565b369c91140724c97b0b9b2d7cfcba741.tar.gz
Do not add handler to event handlers list until ithread is created.
In rare event when fast and ithread interrupts share the same vector and the fast handler was registered first, we can end up trying to schedule the ithread that is not created yet. The kernel built with INVARIANTS then triggers an assertion. Change the order to create the ithread first and only then add the handler that needs it to the interrupt event handlers list. Reviewed by: jhb
-rw-r--r--sys/kern/kern_intr.c52
1 files changed, 27 insertions, 25 deletions
diff --git a/sys/kern/kern_intr.c b/sys/kern/kern_intr.c
index a578084..8e7ac1fc 100644
--- a/sys/kern/kern_intr.c
+++ b/sys/kern/kern_intr.c
@@ -545,17 +545,6 @@ intr_event_add_handler(struct intr_event *ie, const char *name,
}
}
- /* Add the new handler to the event in priority order. */
- TAILQ_FOREACH(temp_ih, &ie->ie_handlers, ih_next) {
- if (temp_ih->ih_pri > ih->ih_pri)
- break;
- }
- if (temp_ih == NULL)
- TAILQ_INSERT_TAIL(&ie->ie_handlers, ih, ih_next);
- else
- TAILQ_INSERT_BEFORE(temp_ih, ih, ih_next);
- intr_event_update(ie);
-
/* Create a thread if we need one. */
while (ie->ie_thread == NULL && handler != NULL) {
if (ie->ie_flags & IE_ADDING_THREAD)
@@ -572,6 +561,18 @@ intr_event_add_handler(struct intr_event *ie, const char *name,
wakeup(ie);
}
}
+
+ /* Add the new handler to the event in priority order. */
+ TAILQ_FOREACH(temp_ih, &ie->ie_handlers, ih_next) {
+ if (temp_ih->ih_pri > ih->ih_pri)
+ break;
+ }
+ if (temp_ih == NULL)
+ TAILQ_INSERT_TAIL(&ie->ie_handlers, ih, ih_next);
+ else
+ TAILQ_INSERT_BEFORE(temp_ih, ih, ih_next);
+ intr_event_update(ie);
+
CTR3(KTR_INTR, "%s: added %s to %s", __func__, ih->ih_name,
ie->ie_name);
mtx_unlock(&ie->ie_lock);
@@ -618,23 +619,12 @@ intr_event_add_handler(struct intr_event *ie, const char *name,
}
}
- /* Add the new handler to the event in priority order. */
- TAILQ_FOREACH(temp_ih, &ie->ie_handlers, ih_next) {
- if (temp_ih->ih_pri > ih->ih_pri)
- break;
- }
- if (temp_ih == NULL)
- TAILQ_INSERT_TAIL(&ie->ie_handlers, ih, ih_next);
- else
- TAILQ_INSERT_BEFORE(temp_ih, ih, ih_next);
- intr_event_update(ie);
-
/* For filtered handlers, create a private ithread to run on. */
- if (filter != NULL && handler != NULL) {
+ if (filter != NULL && handler != NULL) {
mtx_unlock(&ie->ie_lock);
- it = ithread_create("intr: newborn", ih);
+ it = ithread_create("intr: newborn", ih);
mtx_lock(&ie->ie_lock);
- it->it_event = ie;
+ it->it_event = ie;
ih->ih_thread = it;
ithread_update(it); /* XXX - do we really need this?!?!? */
} else { /* Create the global per-event thread if we need one. */
@@ -654,6 +644,18 @@ intr_event_add_handler(struct intr_event *ie, const char *name,
}
}
}
+
+ /* Add the new handler to the event in priority order. */
+ TAILQ_FOREACH(temp_ih, &ie->ie_handlers, ih_next) {
+ if (temp_ih->ih_pri > ih->ih_pri)
+ break;
+ }
+ if (temp_ih == NULL)
+ TAILQ_INSERT_TAIL(&ie->ie_handlers, ih, ih_next);
+ else
+ TAILQ_INSERT_BEFORE(temp_ih, ih, ih_next);
+ intr_event_update(ie);
+
CTR3(KTR_INTR, "%s: added %s to %s", __func__, ih->ih_name,
ie->ie_name);
mtx_unlock(&ie->ie_lock);
OpenPOWER on IntegriCloud