/*
- * Copyright 2016 Facebook, Inc.
+ * Copyright 2017 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*/
#include <folly/detail/Futex.h>
+#include <boost/intrusive/list.hpp>
+#include <folly/Hash.h>
+#include <folly/ScopeGuard.h>
+#include <folly/portability/SysSyscall.h>
#include <stdint.h>
#include <string.h>
+#include <cerrno>
#include <condition_variable>
#include <mutex>
-#include <boost/intrusive/list.hpp>
-#include <folly/Hash.h>
-#include <folly/ScopeGuard.h>
#ifdef __linux__
-# include <errno.h>
-# include <linux/futex.h>
-# include <sys/syscall.h>
+#include <linux/futex.h>
#endif
using namespace std::chrono;
boost::intrusive::list<EmulatedFutexWaitNode> waiters_;
static const size_t kNumBuckets = 4096;
- static EmulatedFutexBucket* gBuckets;
- static std::once_flag gBucketInit;
static EmulatedFutexBucket& bucketFor(void* addr) {
- std::call_once(gBucketInit, [](){
- gBuckets = new EmulatedFutexBucket[kNumBuckets];
- });
+ static auto gBuckets = new EmulatedFutexBucket[kNumBuckets];
uint64_t mixedBits = folly::hash::twang_mix64(
reinterpret_cast<uintptr_t>(addr));
return gBuckets[mixedBits % kNumBuckets];
}
};
-EmulatedFutexBucket* EmulatedFutexBucket::gBuckets;
-std::once_flag EmulatedFutexBucket::gBucketInit;
-
int emulatedFutexWake(void* addr, int count, uint32_t waitMask) {
auto& bucket = EmulatedFutexBucket::bucketFor(addr);
std::unique_lock<std::mutex> bucketLock(bucket.mutex_);
return numAwoken;
}
+template <typename F>
FutexResult emulatedFutexWaitImpl(
- void* addr,
- uint32_t expected,
- time_point<system_clock>* absSystemTime,
- time_point<steady_clock>* absSteadyTime,
- uint32_t waitMask) {
+ F* futex,
+ uint32_t expected,
+ time_point<system_clock>* absSystemTime,
+ time_point<steady_clock>* absSteadyTime,
+ uint32_t waitMask) {
+ static_assert(
+ std::is_same<F, Futex<std::atomic>>::value ||
+ std::is_same<F, Futex<EmulatedFutexAtomic>>::value,
+ "Type F must be either Futex<std::atomic> or Futex<EmulatedFutexAtomic>");
+ void* addr = static_cast<void*>(futex);
auto& bucket = EmulatedFutexBucket::bucketFor(addr);
EmulatedFutexWaitNode node(addr, waitMask);
{
std::unique_lock<std::mutex> bucketLock(bucket.mutex_);
- uint32_t actual;
- memcpy(&actual, addr, sizeof(uint32_t));
- if (actual != expected) {
+ if (futex->load(std::memory_order_relaxed) != expected) {
return FutexResult::VALUE_CHANGED;
}