166 lines · c
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef _LIBCPP___MUTEX_ONCE_FLAG_H10#define _LIBCPP___MUTEX_ONCE_FLAG_H11 12#include <__config>13#include <__memory/addressof.h>14#include <__tuple/tuple_size.h>15#include <__type_traits/invoke.h>16#include <__utility/forward.h>17#include <__utility/integer_sequence.h>18#include <__utility/move.h>19#include <cstdint>20#ifndef _LIBCPP_CXX03_LANG21# include <tuple>22#endif23 24#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)25# pragma GCC system_header26#endif27 28_LIBCPP_PUSH_MACROS29#include <__undef_macros>30 31_LIBCPP_BEGIN_NAMESPACE_STD32 33struct once_flag;34 35#ifndef _LIBCPP_CXX03_LANG36 37template <class _Callable, class... _Args>38_LIBCPP_HIDE_FROM_ABI void call_once(once_flag&, _Callable&&, _Args&&...);39 40#else // _LIBCPP_CXX03_LANG41 42template <class _Callable>43_LIBCPP_HIDE_FROM_ABI void call_once(once_flag&, _Callable&);44 45template <class _Callable>46_LIBCPP_HIDE_FROM_ABI void call_once(once_flag&, const _Callable&);47 48#endif // _LIBCPP_CXX03_LANG49 50struct once_flag {51 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR once_flag() _NOEXCEPT : __state_(_Unset) {}52 once_flag(const once_flag&) = delete;53 once_flag& operator=(const once_flag&) = delete;54 55#if defined(_LIBCPP_ABI_MICROSOFT)56 typedef uintptr_t _State_type;57#else58 typedef unsigned long _State_type;59#endif60 61 static const _State_type _Unset = 0;62 static const _State_type _Pending = 1;63 static const _State_type _Complete = ~_State_type(0);64 65private:66 _State_type __state_;67 68#ifndef _LIBCPP_CXX03_LANG69 template <class _Callable, class... _Args>70 friend void call_once(once_flag&, _Callable&&, _Args&&...);71#else // _LIBCPP_CXX03_LANG72 template <class _Callable>73 friend void call_once(once_flag&, _Callable&);74 75 template <class _Callable>76 friend void call_once(once_flag&, const _Callable&);77#endif // _LIBCPP_CXX03_LANG78};79 80#ifndef _LIBCPP_CXX03_LANG81 82template <class _Fp>83class __call_once_param {84 _Fp& __f_;85 86public:87 _LIBCPP_HIDE_FROM_ABI explicit __call_once_param(_Fp& __f) : __f_(__f) {}88 89 _LIBCPP_HIDE_FROM_ABI void operator()() { __execute(__make_index_sequence<tuple_size<_Fp>::value>()); }90 91private:92 template <size_t... _Indices>93 _LIBCPP_HIDE_FROM_ABI void __execute(__index_sequence<_Indices...>) {94 std::__invoke(std::get<_Indices>(std::move(__f_))...);95 }96};97 98#else99 100template <class _Fp>101class __call_once_param {102 _Fp& __f_;103 104public:105 _LIBCPP_HIDE_FROM_ABI explicit __call_once_param(_Fp& __f) : __f_(__f) {}106 107 _LIBCPP_HIDE_FROM_ABI void operator()() { __f_(); }108};109 110#endif111 112template <class _Fp>113void _LIBCPP_HIDE_FROM_ABI __call_once_proxy(void* __vp) {114 __call_once_param<_Fp>* __p = static_cast<__call_once_param<_Fp>*>(__vp);115 (*__p)();116}117 118_LIBCPP_EXPORTED_FROM_ABI void __call_once(volatile once_flag::_State_type&, void*, void (*)(void*));119 120template <class _ValueType>121inline _LIBCPP_HIDE_FROM_ABI _ValueType __libcpp_acquire_load(_ValueType const* __value) {122#if _LIBCPP_HAS_THREADS123 return __atomic_load_n(__value, __ATOMIC_ACQUIRE);124#else125 return *__value;126#endif127}128 129#ifndef _LIBCPP_CXX03_LANG130 131template <class _Callable, class... _Args>132inline _LIBCPP_HIDE_FROM_ABI void call_once(once_flag& __flag, _Callable&& __func, _Args&&... __args) {133 if (__libcpp_acquire_load(&__flag.__state_) != once_flag::_Complete) {134 typedef tuple<_Callable&&, _Args&&...> _Gp;135 _Gp __f(std::forward<_Callable>(__func), std::forward<_Args>(__args)...);136 __call_once_param<_Gp> __p(__f);137 std::__call_once(__flag.__state_, std::addressof(__p), std::addressof(__call_once_proxy<_Gp>));138 }139}140 141#else // _LIBCPP_CXX03_LANG142 143template <class _Callable>144inline _LIBCPP_HIDE_FROM_ABI void call_once(once_flag& __flag, _Callable& __func) {145 if (__libcpp_acquire_load(&__flag.__state_) != once_flag::_Complete) {146 __call_once_param<_Callable> __p(__func);147 std::__call_once(__flag.__state_, std::addressof(__p), std::addressof(__call_once_proxy<_Callable>));148 }149}150 151template <class _Callable>152inline _LIBCPP_HIDE_FROM_ABI void call_once(once_flag& __flag, const _Callable& __func) {153 if (__libcpp_acquire_load(&__flag.__state_) != once_flag::_Complete) {154 __call_once_param<const _Callable> __p(__func);155 std::__call_once(__flag.__state_, std::addressof(__p), std::addressof(__call_once_proxy<const _Callable>));156 }157}158 159#endif // _LIBCPP_CXX03_LANG160 161_LIBCPP_END_NAMESPACE_STD162 163_LIBCPP_POP_MACROS164 165#endif // _LIBCPP___MUTEX_ONCE_FLAG_H166