Avoid a race between do_hypervisor_event() and stipending() that could
cause an event to be both handled and marked as pending, or being marked as pending twice (triggering the diagnostic check evtch_maskcount[port] == 0 in hypervisor_set_ipending): mask and clear event by word of 32bit in do_hypervisor_event() or stipending(), instead of by indiviual bits in do_event() or xenevt_event(). In addition this is marginally more efficient.
This commit is contained in:
parent
f4a7694fc9
commit
fe7cc0abe1
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: hypervisor_machdep.c,v 1.8 2005/04/18 20:23:56 yamt Exp $ */
|
||||
/* $NetBSD: hypervisor_machdep.c,v 1.9 2005/04/19 22:14:30 bouyer Exp $ */
|
||||
|
||||
/*
|
||||
*
|
||||
|
@ -59,7 +59,7 @@
|
|||
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: hypervisor_machdep.c,v 1.8 2005/04/18 20:23:56 yamt Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: hypervisor_machdep.c,v 1.9 2005/04/19 22:14:30 bouyer Exp $");
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/param.h>
|
||||
|
@ -122,14 +122,18 @@ stipending()
|
|||
l1 &= ~(1 << l1i);
|
||||
|
||||
l2 = s->evtchn_pending[l1i] & ~s->evtchn_mask[l1i];
|
||||
/*
|
||||
* mask and clear event. More efficient than calling
|
||||
* hypervisor_mask/clear_event for each event.
|
||||
*/
|
||||
x86_atomic_setbits_l(&s->evtchn_mask[l1i], l2);
|
||||
x86_atomic_clearbits_l(&s->evtchn_pending[l1i], l2);
|
||||
while ((l2i = ffs(l2)) != 0) {
|
||||
l2i--;
|
||||
l2 &= ~(1 << l2i);
|
||||
|
||||
port = (l1i << 5) + l2i;
|
||||
if (evtsource[port]) {
|
||||
hypervisor_mask_event(port);
|
||||
hypervisor_clear_event(port);
|
||||
hypervisor_set_ipending(port, l1i, l2i);
|
||||
evtsource[port]->ev_evcnt.ev_count++;
|
||||
if (ret == 0 && ci->ci_ilevel <
|
||||
|
@ -181,6 +185,16 @@ do_hypervisor_callback(struct intrframe *regs)
|
|||
l1 &= ~(1 << l1i);
|
||||
|
||||
l2 = s->evtchn_pending[l1i] & ~s->evtchn_mask[l1i];
|
||||
/*
|
||||
* mask and clear the pending events.
|
||||
* Doing it here for all event that will be processed
|
||||
* avoids a race with stipending (which can be called
|
||||
* though do_event->splx) that could cause an event to
|
||||
* be both processed and marked pending.
|
||||
*/
|
||||
x86_atomic_setbits_l(&s->evtchn_mask[l1i], l2);
|
||||
x86_atomic_clearbits_l(&s->evtchn_pending[l1i], l2);
|
||||
|
||||
while ((l2i = ffs(l2)) != 0) {
|
||||
l2i--;
|
||||
l2 &= ~(1 << l2i);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: evtchn.c,v 1.10 2005/04/18 21:31:03 bouyer Exp $ */
|
||||
/* $NetBSD: evtchn.c,v 1.11 2005/04/19 22:14:30 bouyer Exp $ */
|
||||
|
||||
/*
|
||||
*
|
||||
|
@ -34,7 +34,7 @@
|
|||
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: evtchn.c,v 1.10 2005/04/18 21:31:03 bouyer Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: evtchn.c,v 1.11 2005/04/19 22:14:30 bouyer Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
|
@ -163,9 +163,6 @@ do_event(int evtch, struct intrframe *regs)
|
|||
#endif
|
||||
ci = &cpu_info_primary;
|
||||
|
||||
hypervisor_mask_event(evtch);
|
||||
hypervisor_clear_event(evtch);
|
||||
|
||||
/*
|
||||
* Shortcut for the debug handler, we want it to always run,
|
||||
* regardless of the IPL level.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: xenevt.c,v 1.4 2005/04/16 22:49:38 bouyer Exp $ */
|
||||
/* $NetBSD: xenevt.c,v 1.5 2005/04/19 22:14:30 bouyer Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2005 Manuel Bouyer.
|
||||
|
@ -125,9 +125,6 @@ xenevt_event(int port)
|
|||
struct xenevt_d *d;
|
||||
struct cpu_info *ci;
|
||||
|
||||
hypervisor_mask_event(port);
|
||||
hypervisor_clear_event(port);
|
||||
|
||||
d = devevent[port];
|
||||
if (d != NULL) {
|
||||
xenevt_record(d, port);
|
||||
|
|
Loading…
Reference in New Issue