diff options
author | Tavian Barnes <tavianator@tavianator.com> | 2023-07-12 13:12:27 -0400 |
---|---|---|
committer | Tavian Barnes <tavianator@tavianator.com> | 2023-07-12 13:12:27 -0400 |
commit | d9fb2e5e76e1e2de63af78f4de308c3de577c90b (patch) | |
tree | 810cbc53332e2b596838a38591f561ae1e318949 /src/ioq.c | |
parent | dcb6cf524a1d7279457a3e1e7fecff5f46181ab4 (diff) | |
download | bfs-d9fb2e5e76e1e2de63af78f4de308c3de577c90b.tar.xz |
ioq: Try harder to avoid setting IOQ_BLOCKED
Diffstat (limited to 'src/ioq.c')
-rw-r--r-- | src/ioq.c | 22 |
1 files changed, 16 insertions, 6 deletions
@@ -148,20 +148,30 @@ static struct ioqq *ioqq_create(size_t size) { /** Atomically wait for a slot to change. */ static uintptr_t ioq_slot_wait(struct ioqq *ioqq, ioq_slot *slot, uintptr_t value) { - fetch_or(slot, IOQ_BLOCKED, relaxed); - value |= IOQ_BLOCKED; - size_t i = slot - ioqq->slots; struct ioq_monitor *monitor = &ioqq->monitors[i & ioqq->monitor_mask]; mutex_lock(&monitor->mutex); - uintptr_t ret; - while ((ret = load(slot, relaxed)) == value) { + uintptr_t ret = load(slot, relaxed); + if (ret != value) { + goto done; + } + + if (!(value & IOQ_BLOCKED)) { + value |= IOQ_BLOCKED; + if (!compare_exchange_strong(slot, &ret, value, relaxed, relaxed)) { + goto done; + } + } + + do { // To avoid missed wakeups, it is important that // cond_broadcast() is not called right here cond_wait(&monitor->cond, &monitor->mutex); - } + ret = load(slot, relaxed); + } while (ret == value); +done: mutex_unlock(&monitor->mutex); return ret; } |