summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Belopuhov <mikeb@cvs.openbsd.org>2016-08-05 18:31:22 +0000
committerMike Belopuhov <mikeb@cvs.openbsd.org>2016-08-05 18:31:22 +0000
commit89a2a6fe0541ae8b7f1357b2cf4b4bce94d07946 (patch)
tree374ee603ee872abe1615a91ac4b354ecc8f87c2f
parentabbee944d54fce28c21e5ff5ae62eff40a24758b (diff)
Switch pending event clearing to an atomic swap operation
Rather than performing an atomic bit clearing for every encountered event bit set we can adjust the code to perform an atomic swap of a single row of the events array and decrease the amount of expensive atomic operations. Same optimization as for Hyper-V. From FreeBSD.
-rw-r--r--sys/dev/pv/xen.c11
1 files changed, 6 insertions, 5 deletions
diff --git a/sys/dev/pv/xen.c b/sys/dev/pv/xen.c
index 2ec7c4c7230..f03d7459300 100644
--- a/sys/dev/pv/xen.c
+++ b/sys/dev/pv/xen.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: xen.c,v 1.60 2016/08/03 17:14:41 mikeb Exp $ */
+/* $OpenBSD: xen.c,v 1.61 2016/08/05 18:31:21 mikeb Exp $ */
/*
* Copyright (c) 2015 Mike Belopuhov
@@ -628,13 +628,14 @@ xen_intr(void)
for (row = 0; selector > 0; selector >>= 1, row++) {
if ((selector & 1) == 0)
continue;
- pending = sc->sc_ipg->evtchn_pending[row] &
- ~(sc->sc_ipg->evtchn_mask[row]);
+ if ((sc->sc_ipg->evtchn_pending[row] &
+ ~(sc->sc_ipg->evtchn_mask[row])) == 0)
+ continue;
+ pending = atomic_swap_ulong(&sc->sc_ipg->evtchn_pending[row],
+ 0) & ~(sc->sc_ipg->evtchn_mask[row]);
for (bit = 0; pending > 0; pending >>= 1, bit++) {
if ((pending & 1) == 0)
continue;
- atomic_clearbit_ptr(&sc->sc_ipg->evtchn_pending[row],
- bit);
port = (row * LONG_BIT) + bit;
if ((xi = xen_lookup_intsrc(sc, port)) == NULL) {
printf("%s: unhandled interrupt on port %u\n",