PERFORCE change 101208 for review
Paolo Pisati
piso at FreeBSD.org
Mon Jul 10 15:34:16 UTC 2006
http://perforce.freebsd.org/chv.cgi?CH=101208
Change 101208 by piso at piso_newluxor on 2006/07/10 15:33:30
Correct the execution logic of interrupts as pointed out
by jhb:
-if a filter completely served the interrupt (FILTER_HANDLED),
return immediately and eoi the source.
-if a filter wants to run the handler in ithread
(FILTER_SCHEDULE_ITHREAD) stamp ih_need, mask & eoi the source
and schedule the ithread.
-if no handlers with filter were present, then run
all the filter-less handlers (if present).
In kern_intr.c::ithread_execute_handlers() execute only
sw & hw interrupts that have ih_need set.
Unfortunately, the screen of my laptop still doesn't get
refreshed properly:
it does boot fine, but after it mounts the disk, the screen
isn't refreshed anymore up to the next printf() from kernel
land.
In fact, the only way to see what's going on is to break
to ddb (CTRL+ALT+ESC), the debugger tries to print something
on the screen and magically all the output that was previously
missing gets flushed to screen and i can see that it reached
the login prompt fine, i can log, issue commands and so on
(everything blindly of course) with no problems.
Affected files ...
.. //depot/projects/soc2006/intr_filter/i386/i386/intr_machdep.c#6 edit
.. //depot/projects/soc2006/intr_filter/kern/kern_intr.c#6 edit
Differences ...
==== //depot/projects/soc2006/intr_filter/i386/i386/intr_machdep.c#6 (text+ko) ====
@@ -215,18 +215,19 @@
thread = intr_filter_loop(ie, frame);
/*
- * If there are any threaded handlers that need to run,
- * mask the source as well as sending it an EOI. Otherwise,
- * just send it an EOI but leave it unmasked.
+ * If the interrupt was fully served, send it an EOI but leave it
+ * unmasked. Otherwise, if there are any threaded handlers that need
+ * to run or it was a stray interrupt, mask the source as well as
+ * sending it an EOI.
*/
- if (thread)
+ if (thread & FILTER_HANDLED)
+ isrc->is_pic->pic_eoi_source(isrc);
+ else
isrc->is_pic->pic_disable_source(isrc, PIC_EOI);
- else
- isrc->is_pic->pic_eoi_source(isrc);
critical_exit();
/* Schedule the ithread if needed. */
- if (thread) {
+ if (thread & FILTER_SCHEDULE_THREAD) {
error = intr_event_schedule_thread(ie);
KASSERT(error == 0, ("bad stray interrupt"));
}
==== //depot/projects/soc2006/intr_filter/kern/kern_intr.c#6 (text+ko) ====
@@ -638,29 +638,17 @@
}
/*
- * For software interrupt threads, we only execute
- * handlers that have their need flag set. Hardware
- * interrupt threads always invoke all of their handlers.
+ * Execute handlers that have their need flag set.
*/
- if (ie->ie_flags & IE_SOFT) {
- if (!ih->ih_need)
- continue;
- else
- atomic_store_rel_int(&ih->ih_need, 0);
- }
+ if (!ih->ih_need)
+ continue;
+ else
+ atomic_store_rel_int(&ih->ih_need, 0);
/* Fast handlers are handled in primary interrupt context. */
if (ih->ih_flags & IH_FAST)
continue;
- /* Execute handlers of filters that need it. */
- if (ih->ih_filter != NULL) {
- if (!ih->ih_need)
- continue;
- else
- atomic_store_rel_int(&ih->ih_need, 0);
- }
-
/* Execute this handler. */
CTR6(KTR_INTR, "%s: pid %d exec %p(%p) for %s flg=%x",
__func__, p->p_pid, (void *)ih->ih_handler, ih->ih_argument,
@@ -785,10 +773,11 @@
intr_filter_loop(struct intr_event *ie, struct trapframe *frame) {
struct intr_handler *ih;
void *arg;
- int ret, ret2 = 0;
+ int ret, ret2, thread_only;
+ ret = 0;
+ thread_only = 0;
TAILQ_FOREACH(ih, &ie->ie_handlers, ih_next) {
- ih->ih_need = 0;
/*
* Execute fast interrupt handlers directly.
* To support clock handlers, if a handler registers
@@ -801,28 +790,48 @@
ih->ih_filter, ih->ih_handler, arg, ih->ih_name);
if (ih->ih_filter != NULL)
- ret = ih->ih_filter(arg);
+ ret2 = ih->ih_filter(arg);
else {
- /* legacy ithread handler */
- ret2 = 1;
+ /* Legacy ithread only handler. */
+ thread_only = 1;
continue;
}
- /* try with the next handler... */
- if (ret == FILTER_STRAY)
+ /* Mark handler for later execution in ithread. */
+ if (ret2 == FILTER_SCHEDULE_THREAD) {
+ ih->ih_need = 1;
+ ret |= FILTER_SCHEDULE_THREAD;
continue;
+ }
+
+ /* Interrupt served in filter. */
+ if (ret2 == FILTER_HANDLED) {
+ ret |= FILTER_HANDLED;
+ return (ret);
+ }
+ }
- /* interrupt served in filter */
- if (ret == FILTER_HANDLED)
- continue;
+ /*
+ * A filter did claim the interrupt but didn't shut it up
+ * fully, so schedule the ithread.
+ */
+ if (ret != 0)
+ return (ret);
- /* mark handler for later execution */
- if (ret == FILTER_SCHEDULE_THREAD) {
- ih->ih_need = 1;
- ret2 = 1;
+ /*
+ * No filters handled the interrupt and we have at least
+ * one handler without a filter. In this case, we schedule
+ * all of the filter-less handlers to run in the ithread.
+ */
+ if (thread_only) {
+ TAILQ_FOREACH(ih, &ie->ie_handlers, ih_next) {
+ if (ih->ih_filter != NULL)
+ continue;
+ ih->ih_need = 1;
}
+ return (FILTER_SCHEDULE_THREAD);
}
- return(ret2);
+ return (FILTER_STRAY);
}
More information about the p4-projects
mailing list