From 01892c70d5f8043d35b5eaca42db3e69bcbab05e Mon Sep 17 00:00:00 2001 From: Vadim Skipin Date: Thu, 7 May 2026 10:50:05 +0000 Subject: [PATCH] Fix waiter-table hashing --- include/silk/util/platform.h | 11 +++++++++++ src/fibers/fiber.cpp | 7 ++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/include/silk/util/platform.h b/include/silk/util/platform.h index 28a9270..945eec5 100644 --- a/include/silk/util/platform.h +++ b/include/silk/util/platform.h @@ -118,6 +118,17 @@ static inline uint64_t getTimeNanoseconds() noexcept return static_cast(ts.tv_sec) * 1'000'000'000 + static_cast(ts.tv_nsec); } +/** 64-bit integer hash (Murmur3 fmix64 finalizer). */ +static constexpr uint64_t intHash(uint64_t key) noexcept +{ + key ^= key >> 33; + key *= 0xff51afd7ed558ccdULL; + key ^= key >> 33; + key *= 0xc4ceb9fe1a85ec53ULL; + key ^= key >> 33; + return key; +} + /** * Initialize librseq. Must be called before any rseq critical sections run. * Idempotent -- safe to call multiple times. diff --git a/src/fibers/fiber.cpp b/src/fibers/fiber.cpp index f9e5191..361ff0a 100644 --- a/src/fibers/fiber.cpp +++ b/src/fibers/fiber.cpp @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -58,6 +57,8 @@ static constexpr uint64_t CQE_TAG_CANCEL = 0; static constexpr uint64_t CQE_TAG_TIMEOUT = 1; static constexpr uint64_t CQE_TAG_DOORBELL = 2; +static_assert((WAITER_TABLE_SIZE & (WAITER_TABLE_SIZE - 1)) == 0); + // clang-format off #define FIBER_SIMPLE_COUNTERS(x) \ x(FIBER_STARTED, "FiberStarted") \ @@ -1192,7 +1193,7 @@ void FiberScheduler::suspend(SuspendCallback * callback, void * context) noexcep void FiberScheduler::enqueueWaiter(uint64_t key, Fiber * fiber) noexcept { - uint64_t index = std::hash{}(key) % WAITER_TABLE_SIZE; + uint64_t index = intHash(key) & (WAITER_TABLE_SIZE - 1); scheduler->waiterTable[index].push(fiber); // seq_cst fence pairs with the one in releaseWaiters to prevent the @@ -1207,7 +1208,7 @@ void FiberScheduler::releaseWaiters(uint64_t key) noexcept // seq_cst fence pairs with the one in enqueueWaiter. std::atomic_thread_fence(std::memory_order_seq_cst); - uint64_t index = std::hash{}(key) % WAITER_TABLE_SIZE; + uint64_t index = intHash(key) & (WAITER_TABLE_SIZE - 1); Fiber * fiber = scheduler->waiterTable[index].popAll(); while (fiber) {