Extend critical section coverage in the low-level interrupt handlers to

include the ithread scheduling step.  Without this, a preemption might
occur in between the interrupt getting masked and the ithread getting
scheduled.  Since the interrupt handler runs in the context of curthread,
the scheudler might see it as having a such a low priority on a busy system
that it doesn't get to run for a _long_ time, leaving the interrupt stranded
in a disabled state.  The only way that the preemption can happen is by
a fast/filter handler triggering a schduling event earlier in the handler,
so this problem can only happen for cases where an interrupt is being
shared by both a fast/filter handler and an ithread handler.  Unfortunately,
it seems to be common for this sharing to happen with network and USB
devices, for example.  This fixes many of the mysterious TCP session
timeouts and NIC watchdogs that were being reported.  Many thanks to Sam
Lefler for getting to the bottom of this problem.

Reviewed by: jhb, jeff, silby
This commit is contained in:
Scott Long 2007-11-21 04:03:51 +00:00
parent 3e636fa0e5
commit 8611774e5e
5 changed files with 5 additions and 5 deletions

View File

@ -390,13 +390,13 @@ intr_execute_handlers(struct intsrc *isrc, struct trapframe *frame)
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) {
error = intr_event_schedule_thread(ie);
KASSERT(error == 0, ("bad stray interrupt"));
}
critical_exit();
td->td_intr_nesting_level--;
}
#endif

View File

@ -391,13 +391,13 @@ intr_execute_handlers(struct intsrc *isrc, struct trapframe *frame)
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) {
error = intr_event_schedule_thread(ie);
KASSERT(error == 0, ("bad stray interrupt"));
}
critical_exit();
td->td_intr_nesting_level--;
}
#endif

View File

@ -441,7 +441,6 @@ ia64_dispatch_intr(void *frame, u_int vector)
thread = 1;
}
}
critical_exit();
if (thread) {
ia64_intr_mask((void *)(uintptr_t)vector);
@ -449,6 +448,7 @@ ia64_dispatch_intr(void *frame, u_int vector)
KASSERT(error == 0, ("%s: impossible stray", __func__));
} else
ia64_intr_eoi((void *)(uintptr_t)vector);
critical_exit();
#endif
}

View File

@ -280,7 +280,6 @@ powerpc_dispatch_intr(u_int vector, struct trapframe *tf)
sched = 1;
}
}
critical_exit();
if (sched) {
PIC_MASK(pic, i->irq);
@ -289,6 +288,7 @@ powerpc_dispatch_intr(u_int vector, struct trapframe *tf)
__func__));
} else
PIC_EOI(pic, i->irq);
critical_exit();
#endif
return;

View File

@ -286,7 +286,6 @@ intr_execute_handlers(void *cookie)
}
if (!thread)
intr_enable_eoi(iv);
critical_exit();
/* Schedule a heavyweight interrupt process. */
if (thread)
@ -295,6 +294,7 @@ intr_execute_handlers(void *cookie)
error = EINVAL;
else
error = 0;
critical_exit();
if (error == EINVAL)
#else
if (intr_event_handle(iv->iv_event, NULL) != 0)