summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormikeb <mikeb@openbsd.org>2016-08-05 18:16:04 +0000
committermikeb <mikeb@openbsd.org>2016-08-05 18:16:04 +0000
commitef2198aad1cba51dff27ca5c9680c6c9a5fc608b (patch)
treee1a87e3b559d61baf10b0d63f63f94d0a450e0bf
parentFixup incorrect EAGAIN handling (diff)
downloadwireguard-openbsd-ef2198aad1cba51dff27ca5c9680c6c9a5fc608b.tar.xz
wireguard-openbsd-ef2198aad1cba51dff27ca5c9680c6c9a5fc608b.zip
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. From FreeBSD.
-rw-r--r--sys/dev/pv/hyperv.c7
1 files changed, 4 insertions, 3 deletions
diff --git a/sys/dev/pv/hyperv.c b/sys/dev/pv/hyperv.c
index 1aba89795e1..7a8e22cca19 100644
--- a/sys/dev/pv/hyperv.c
+++ b/sys/dev/pv/hyperv.c
@@ -534,7 +534,7 @@ hv_event_intr(struct hv_softc *sc)
int cpu = CPU_INFO_UNIT(ci);
int bit, dword, maxdword, relid;
struct hv_channel *ch;
- uint32_t *revents;
+ uint32_t *revents, pending;
evt = (struct hv_synic_event_flags *)sc->sc_siep[cpu] + HV_MESSAGE_SINT;
if ((sc->sc_proto == HV_VMBUS_VERSION_WS2008) ||
@@ -559,8 +559,9 @@ hv_event_intr(struct hv_softc *sc)
for (dword = 0; dword < maxdword; dword++) {
if (revents[dword] == 0)
continue;
- for (bit = 0; bit < 32; bit++) {
- if (!atomic_clearbit_ptr(&revents[dword], bit))
+ pending = atomic_swap_uint(&revents[dword], 0);
+ for (bit = 0; pending > 0; pending >>= 1, bit++) {
+ if ((pending & 1) == 0)
continue;
relid = (dword << 5) + bit;
/* vmbus channel protocol message */