adding a fibers compatible once flag
[folly.git] / folly / synchronization / CallOnce.h
index da938beb069a07864dd28f86ab620ae3cd5eeec4..4d4bf0f4b80a812f460a05428bfcd027903ea68e 100644 (file)
 #include <folly/SharedMutex.h>
 
 namespace folly {
+namespace detail {
+template <typename Mutex>
+class once_flag;
 
-class once_flag {
- public:
-  constexpr once_flag() noexcept = default;
-  once_flag(const once_flag&) = delete;
-  once_flag& operator=(const once_flag&) = delete;
+// Implementation detail: out-of-line slow path
+template <class Mutex, class Callable, class... Args>
+void FOLLY_NOINLINE call_once_impl_no_inline(
+    detail::once_flag<Mutex>& flag,
+    Callable&& f,
+    Args&&... args) {
+  std::lock_guard<Mutex> lg(flag.mutex_);
+  if (flag.called_) {
+    return;
+  }
 
-  template <typename Callable, class... Args>
-  friend void call_once(once_flag& flag, Callable&& f, Args&&... args);
-  template <typename Callable, class... Args>
-  friend void call_once_impl_no_inline(once_flag& flag,
-                                       Callable&& f,
-                                       Args&&... args);
+  std::forward<Callable>(f)(std::forward<Args>(args)...);
 
- private:
-  std::atomic<bool> called_{false};
-  folly::SharedMutex mutex_;
-};
+  flag.called_.store(true, std::memory_order_release);
+}
+} // namespace detail
 
-template <class Callable, class... Args>
+using once_flag = detail::once_flag<folly::SharedMutex>;
+
+template <class Mutex, class Callable, class... Args>
 void FOLLY_ALWAYS_INLINE
-call_once(once_flag& flag, Callable&& f, Args&&... args) {
+call_once(detail::once_flag<Mutex>& flag, Callable&& f, Args&&... args) {
   if (LIKELY(flag.called_.load(std::memory_order_acquire))) {
     return;
   }
@@ -68,17 +72,30 @@ call_once(once_flag& flag, Callable&& f, Args&&... args) {
       flag, std::forward<Callable>(f), std::forward<Args>(args)...);
 }
 
-// Implementation detail: out-of-line slow path
-template <class Callable, class... Args>
-void FOLLY_NOINLINE
-call_once_impl_no_inline(once_flag& flag, Callable&& f, Args&&... args) {
-  std::lock_guard<folly::SharedMutex> lg(flag.mutex_);
-  if (flag.called_) {
-    return;
-  }
+namespace detail {
 
-  std::forward<Callable>(f)(std::forward<Args>(args)...);
+template <typename Mutex>
+class once_flag {
+ public:
+  constexpr once_flag() noexcept = default;
+  once_flag(const once_flag&) = delete;
+  once_flag& operator=(const once_flag&) = delete;
+
+  template <typename Mutex_, typename Callable, class... Args>
+  friend void ::folly::call_once(
+      once_flag<Mutex_>& flag,
+      Callable&& f,
+      Args&&... args);
+  template <typename Mutex_, typename Callable, class... Args>
+  friend void call_once_impl_no_inline(
+      once_flag<Mutex_>& flag,
+      Callable&& f,
+      Args&&... args);
+
+ private:
+  std::atomic<bool> called_{false};
+  Mutex mutex_;
+};
+} // namespace detail
 
-  flag.called_.store(true, std::memory_order_release);
-}
 } // namespace folly