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:
bouyer 2005-04-19 22:14:30 +00:00
parent f4a7694fc9
commit fe7cc0abe1
3 changed files with 21 additions and 13 deletions

View File

@ -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);

View File

@ -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.

View File

@ -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);