#include <folly/Likely.h>
#include <folly/Portability.h>
+#include <folly/SharedMutex.h>
namespace folly {
private:
std::atomic<bool> called_{false};
- std::once_flag std_once_flag_;
+ folly::SharedMutex mutex_;
};
template <class Callable, class... Args>
template <class Callable, class... Args>
void FOLLY_NOINLINE
call_once_impl_no_inline(once_flag& flag, Callable&& f, Args&&... args) {
- std::call_once(flag.std_once_flag_,
- std::forward<Callable>(f),
- std::forward<Args>(args)...);
+ std::lock_guard<folly::SharedMutex> lg(flag.mutex_);
+ if (flag.called_) {
+ return;
+ }
+
+ std::forward<Callable>(f)(std::forward<Args>(args)...);
+
flag.called_.store(true, std::memory_order_release);
}
}
class UpgradeHolder;
class WriteHolder;
- constexpr SharedMutexImpl() : state_(0) {}
+ constexpr SharedMutexImpl() noexcept : state_(0) {}
SharedMutexImpl(const SharedMutexImpl&) = delete;
SharedMutexImpl(SharedMutexImpl&&) = delete;
#include <condition_variable>
#include <mutex>
#include <boost/intrusive/list.hpp>
-#include <folly/CallOnce.h>
#include <folly/Hash.h>
#include <folly/ScopeGuard.h>
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];
- });
+ 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;
-folly::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_);
ASSERT_EQ(1, out);
}
+TEST(FollyCallOnce, Exception) {
+ struct ExpectedException {};
+ folly::once_flag flag;
+ size_t numCalls = 0;
+ EXPECT_THROW(
+ folly::call_once(
+ flag,
+ [&] {
+ ++numCalls;
+ throw ExpectedException();
+ }),
+ ExpectedException);
+ EXPECT_EQ(1, numCalls);
+ folly::call_once(flag, [&] { ++numCalls; });
+ EXPECT_EQ(2, numCalls);
+}
+
TEST(FollyCallOnce, Stress) {
for (int i = 0; i < 100; ++i) {
folly::once_flag flag;