-// Our emulated futex uses 4096 lists of wait nodes. There are two levels
-// of locking: a per-list mutex that controls access to the list and a
-// per-node mutex, condvar, and bool that are used for the actual wakeups.
-// The per-node mutex allows us to do precise wakeups without thundering
-// herds.
-
-struct EmulatedFutexWaitNode : public boost::intrusive::list_base_hook<> {
- void* const addr_;
- const uint32_t waitMask_;
-
- // tricky: hold both bucket and node mutex to write, either to read
- bool signaled_;
- std::mutex mutex_;
- std::condition_variable cond_;
-
- EmulatedFutexWaitNode(void* addr, uint32_t waitMask)
- : addr_(addr)
- , waitMask_(waitMask)
- , signaled_(false)
- {
- }
-};
-
-struct EmulatedFutexBucket {
- std::mutex mutex_;
- boost::intrusive::list<EmulatedFutexWaitNode> waiters_;
-
- static const size_t kNumBuckets = 4096;
- static EmulatedFutexBucket* gBuckets;
- static folly::once_flag gBucketInit;
-
- static EmulatedFutexBucket& bucketFor(void* addr) {
- folly::call_once(gBucketInit, [](){
- gBuckets = new EmulatedFutexBucket[kNumBuckets];
- });
- uint64_t mixedBits = folly::hash::twang_mix64(
- reinterpret_cast<uintptr_t>(addr));
- return gBuckets[mixedBits % kNumBuckets];
- }
-};
-
-EmulatedFutexBucket* EmulatedFutexBucket::gBuckets;
-folly::once_flag EmulatedFutexBucket::gBucketInit;