/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * 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. */ // // Docs: https://fburl.com/fbcref_callonce // #pragma once #include <atomic> #include <utility> #include <folly/Likely.h> #include <folly/MicroLock.h> #include <folly/Portability.h> #include <folly/SharedMutex.h> #include <folly/functional/Invoke.h> namespace folly { /** * The flag template to be used with call_once. Parameterizable by the mutex * type and atomic template. The mutex type is required to mimic std::mutex and * the atomic type is required to mimic std::atomic. */ template <typename Mutex, template <typename> class Atom = std::atomic> class basic_once_flag; /** * An alternative flag template that can be used with call_once that uses only * 1 byte. Internally, compact_once_flag uses folly::MicroLock and its data * storage API. */ class compact_once_flag; /** * Drop-in replacement for std::call_once. * * The libstdc++ implementation has two flaws: * * it lacks a fast path, and * * it deadlocks (in explicit violation of the standard) when invoked twice * with a given flag, and the callable passed to the first invocation throws. * * This implementation corrects both flaws. * * The tradeoff is a slightly larger once_flag struct at 8 bytes, vs 4 bytes * with libstdc++ on Linux/x64. However, you may use folly::compact_once_flag * which is 1 byte. * * Does not work with std::once_flag. * * mimic: std::call_once */ template <typename OnceFlag, typename F, typename... Args> FOLLY_ALWAYS_INLINE void call_once(OnceFlag& flag, F&& f, Args&&... args) { … } /** * Like call_once, but using a boolean return type to signal pass/fail rather * than throwing exceptions. * * Returns true if any previous call to try_call_once with the same once_flag * has returned true or if any previous call to call_once with the same * once_flag has completed without throwing an exception or if the function * passed as an argument returns true; otherwise returns false. * * Note: This has no parallel in the std::once_flag interface. */ template <typename OnceFlag, typename F, typename... Args> FOLLY_NODISCARD FOLLY_ALWAYS_INLINE bool try_call_once( OnceFlag& flag, F&& f, Args&&... args) noexcept { … } /** * Tests whether any invocation to call_once with the given flag has succeeded. * * May help with space usage in certain esoteric scenarios compared with caller * code tracking a separate and possibly-padded bool. * * Note: This has no parallel in the std::once_flag interface. */ template <typename OnceFlag> FOLLY_ALWAYS_INLINE bool test_once(OnceFlag const& flag) noexcept { … } /** * Resets a flag. * * Warning: unsafe to call concurrently with any other flag operations. */ template <typename OnceFlag> FOLLY_ALWAYS_INLINE void reset_once(OnceFlag& flag) noexcept { … } /** * Sets a flag, as if call_once(flag, [] {}) was called. * * Warning: unsafe to call concurrently with any other flag operations. */ template <typename OnceFlag> FOLLY_ALWAYS_INLINE void set_once(OnceFlag& flag) noexcept { … } template <typename Mutex, template <typename> class Atom> class basic_once_flag { … }; class compact_once_flag { … }; static_assert …; /** * The flag type to be used with call_once. An instance of basic_once_flag. * * Does not work with std::call_once. * * mimic: std::once_flag */ once_flag; } // namespace folly