Commit b529367b authored by Shubhanshu Agrawal's avatar Shubhanshu Agrawal Committed by Facebook Github Bot

adding a fibers compatible once flag

Summary:
The current folly::once_flag is not compatible with folly fibers
and when using it with fibers is inefficient and also cause deadlocks.

This diff makes the once flag's mutex be a templatable paramter
and overrides it in fibers library with a fiber compatible mtuex.

Reviewed By: yfeldblum

Differential Revision: D6288508

fbshipit-source-id: 6f82e1794d1f417f8d267061f1702a26a7b4ff12
parent 98c488e2
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "folly/fibers/TimedMutex.h"
#include "folly/synchronization/CallOnce.h"
namespace folly {
namespace fibers {
using once_flag = ::folly::detail::once_flag<folly::fibers::TimedMutex>;
}
} // namespace folly
...@@ -29,7 +29,7 @@ namespace fibers { ...@@ -29,7 +29,7 @@ namespace fibers {
**/ **/
class TimedMutex { class TimedMutex {
public: public:
TimedMutex() {} TimedMutex() noexcept {}
~TimedMutex() { ~TimedMutex() {
DCHECK(threadWaiters_.empty()); DCHECK(threadWaiters_.empty());
......
...@@ -39,28 +39,32 @@ ...@@ -39,28 +39,32 @@
#include <folly/SharedMutex.h> #include <folly/SharedMutex.h>
namespace folly { namespace folly {
namespace detail {
template <typename Mutex>
class once_flag;
class once_flag { // Implementation detail: out-of-line slow path
public: template <class Mutex, class Callable, class... Args>
constexpr once_flag() noexcept = default; void FOLLY_NOINLINE call_once_impl_no_inline(
once_flag(const once_flag&) = delete; detail::once_flag<Mutex>& flag,
once_flag& operator=(const once_flag&) = delete; Callable&& f,
Args&&... args) {
std::lock_guard<Mutex> lg(flag.mutex_);
if (flag.called_) {
return;
}
template <typename Callable, class... Args> std::forward<Callable>(f)(std::forward<Args>(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);
private: flag.called_.store(true, std::memory_order_release);
std::atomic<bool> called_{false}; }
folly::SharedMutex mutex_; } // 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 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))) { if (LIKELY(flag.called_.load(std::memory_order_acquire))) {
return; return;
} }
...@@ -68,17 +72,30 @@ call_once(once_flag& flag, Callable&& f, Args&&... args) { ...@@ -68,17 +72,30 @@ call_once(once_flag& flag, Callable&& f, Args&&... args) {
flag, std::forward<Callable>(f), std::forward<Args>(args)...); flag, std::forward<Callable>(f), std::forward<Args>(args)...);
} }
// Implementation detail: out-of-line slow path namespace detail {
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;
}
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 } // namespace folly
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment