xref: /freebsd/contrib/llvm-project/libcxx/include/__mutex/once_flag.h (revision b3edf4467982447620505a28fc82e38a414c07dc)
15f757f3fSDimitry Andric //===----------------------------------------------------------------------===//
25f757f3fSDimitry Andric //
35f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65f757f3fSDimitry Andric //
75f757f3fSDimitry Andric //===----------------------------------------------------------------------===//
85f757f3fSDimitry Andric 
95f757f3fSDimitry Andric #ifndef _LIBCPP___MUTEX_ONCE_FLAG_H
105f757f3fSDimitry Andric #define _LIBCPP___MUTEX_ONCE_FLAG_H
115f757f3fSDimitry Andric 
125f757f3fSDimitry Andric #include <__config>
135f757f3fSDimitry Andric #include <__functional/invoke.h>
145f757f3fSDimitry Andric #include <__memory/shared_ptr.h> // __libcpp_acquire_load
155f757f3fSDimitry Andric #include <__tuple/tuple_indices.h>
165f757f3fSDimitry Andric #include <__tuple/tuple_size.h>
175f757f3fSDimitry Andric #include <__utility/forward.h>
185f757f3fSDimitry Andric #include <__utility/move.h>
195f757f3fSDimitry Andric #include <cstdint>
205f757f3fSDimitry Andric #ifndef _LIBCPP_CXX03_LANG
215f757f3fSDimitry Andric #  include <tuple>
225f757f3fSDimitry Andric #endif
235f757f3fSDimitry Andric 
245f757f3fSDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
255f757f3fSDimitry Andric #  pragma GCC system_header
265f757f3fSDimitry Andric #endif
275f757f3fSDimitry Andric 
28*b3edf446SDimitry Andric _LIBCPP_PUSH_MACROS
29*b3edf446SDimitry Andric #include <__undef_macros>
30*b3edf446SDimitry Andric 
315f757f3fSDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD
325f757f3fSDimitry Andric 
335f757f3fSDimitry Andric struct _LIBCPP_TEMPLATE_VIS once_flag;
345f757f3fSDimitry Andric 
355f757f3fSDimitry Andric #ifndef _LIBCPP_CXX03_LANG
365f757f3fSDimitry Andric 
375f757f3fSDimitry Andric template <class _Callable, class... _Args>
385f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI void call_once(once_flag&, _Callable&&, _Args&&...);
395f757f3fSDimitry Andric 
405f757f3fSDimitry Andric #else // _LIBCPP_CXX03_LANG
415f757f3fSDimitry Andric 
425f757f3fSDimitry Andric template <class _Callable>
435f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI void call_once(once_flag&, _Callable&);
445f757f3fSDimitry Andric 
455f757f3fSDimitry Andric template <class _Callable>
465f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI void call_once(once_flag&, const _Callable&);
475f757f3fSDimitry Andric 
485f757f3fSDimitry Andric #endif // _LIBCPP_CXX03_LANG
495f757f3fSDimitry Andric 
505f757f3fSDimitry Andric struct _LIBCPP_TEMPLATE_VIS once_flag {
515f757f3fSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR once_flag() _NOEXCEPT : __state_(_Unset) {}
525f757f3fSDimitry Andric   once_flag(const once_flag&)            = delete;
535f757f3fSDimitry Andric   once_flag& operator=(const once_flag&) = delete;
545f757f3fSDimitry Andric 
555f757f3fSDimitry Andric #if defined(_LIBCPP_ABI_MICROSOFT)
565f757f3fSDimitry Andric   typedef uintptr_t _State_type;
575f757f3fSDimitry Andric #else
585f757f3fSDimitry Andric   typedef unsigned long _State_type;
595f757f3fSDimitry Andric #endif
605f757f3fSDimitry Andric 
615f757f3fSDimitry Andric   static const _State_type _Unset    = 0;
625f757f3fSDimitry Andric   static const _State_type _Pending  = 1;
635f757f3fSDimitry Andric   static const _State_type _Complete = ~_State_type(0);
645f757f3fSDimitry Andric 
655f757f3fSDimitry Andric private:
665f757f3fSDimitry Andric   _State_type __state_;
675f757f3fSDimitry Andric 
685f757f3fSDimitry Andric #ifndef _LIBCPP_CXX03_LANG
695f757f3fSDimitry Andric   template <class _Callable, class... _Args>
705f757f3fSDimitry Andric   friend void call_once(once_flag&, _Callable&&, _Args&&...);
715f757f3fSDimitry Andric #else  // _LIBCPP_CXX03_LANG
725f757f3fSDimitry Andric   template <class _Callable>
735f757f3fSDimitry Andric   friend void call_once(once_flag&, _Callable&);
745f757f3fSDimitry Andric 
755f757f3fSDimitry Andric   template <class _Callable>
765f757f3fSDimitry Andric   friend void call_once(once_flag&, const _Callable&);
775f757f3fSDimitry Andric #endif // _LIBCPP_CXX03_LANG
785f757f3fSDimitry Andric };
795f757f3fSDimitry Andric 
805f757f3fSDimitry Andric #ifndef _LIBCPP_CXX03_LANG
815f757f3fSDimitry Andric 
825f757f3fSDimitry Andric template <class _Fp>
835f757f3fSDimitry Andric class __call_once_param {
845f757f3fSDimitry Andric   _Fp& __f_;
855f757f3fSDimitry Andric 
865f757f3fSDimitry Andric public:
875f757f3fSDimitry Andric   _LIBCPP_HIDE_FROM_ABI explicit __call_once_param(_Fp& __f) : __f_(__f) {}
885f757f3fSDimitry Andric 
895f757f3fSDimitry Andric   _LIBCPP_HIDE_FROM_ABI void operator()() {
905f757f3fSDimitry Andric     typedef typename __make_tuple_indices<tuple_size<_Fp>::value, 1>::type _Index;
915f757f3fSDimitry Andric     __execute(_Index());
925f757f3fSDimitry Andric   }
935f757f3fSDimitry Andric 
945f757f3fSDimitry Andric private:
955f757f3fSDimitry Andric   template <size_t... _Indices>
965f757f3fSDimitry Andric   _LIBCPP_HIDE_FROM_ABI void __execute(__tuple_indices<_Indices...>) {
975f757f3fSDimitry Andric     std::__invoke(std::get<0>(std::move(__f_)), std::get<_Indices>(std::move(__f_))...);
985f757f3fSDimitry Andric   }
995f757f3fSDimitry Andric };
1005f757f3fSDimitry Andric 
1015f757f3fSDimitry Andric #else
1025f757f3fSDimitry Andric 
1035f757f3fSDimitry Andric template <class _Fp>
1045f757f3fSDimitry Andric class __call_once_param {
1055f757f3fSDimitry Andric   _Fp& __f_;
1065f757f3fSDimitry Andric 
1075f757f3fSDimitry Andric public:
1085f757f3fSDimitry Andric   _LIBCPP_HIDE_FROM_ABI explicit __call_once_param(_Fp& __f) : __f_(__f) {}
1095f757f3fSDimitry Andric 
1105f757f3fSDimitry Andric   _LIBCPP_HIDE_FROM_ABI void operator()() { __f_(); }
1115f757f3fSDimitry Andric };
1125f757f3fSDimitry Andric 
1135f757f3fSDimitry Andric #endif
1145f757f3fSDimitry Andric 
1155f757f3fSDimitry Andric template <class _Fp>
1165f757f3fSDimitry Andric void _LIBCPP_HIDE_FROM_ABI __call_once_proxy(void* __vp) {
1175f757f3fSDimitry Andric   __call_once_param<_Fp>* __p = static_cast<__call_once_param<_Fp>*>(__vp);
1185f757f3fSDimitry Andric   (*__p)();
1195f757f3fSDimitry Andric }
1205f757f3fSDimitry Andric 
1215f757f3fSDimitry Andric _LIBCPP_EXPORTED_FROM_ABI void __call_once(volatile once_flag::_State_type&, void*, void (*)(void*));
1225f757f3fSDimitry Andric 
1235f757f3fSDimitry Andric #ifndef _LIBCPP_CXX03_LANG
1245f757f3fSDimitry Andric 
1255f757f3fSDimitry Andric template <class _Callable, class... _Args>
1265f757f3fSDimitry Andric inline _LIBCPP_HIDE_FROM_ABI void call_once(once_flag& __flag, _Callable&& __func, _Args&&... __args) {
1275f757f3fSDimitry Andric   if (__libcpp_acquire_load(&__flag.__state_) != once_flag::_Complete) {
1285f757f3fSDimitry Andric     typedef tuple<_Callable&&, _Args&&...> _Gp;
1295f757f3fSDimitry Andric     _Gp __f(std::forward<_Callable>(__func), std::forward<_Args>(__args)...);
1305f757f3fSDimitry Andric     __call_once_param<_Gp> __p(__f);
1315f757f3fSDimitry Andric     std::__call_once(__flag.__state_, &__p, &__call_once_proxy<_Gp>);
1325f757f3fSDimitry Andric   }
1335f757f3fSDimitry Andric }
1345f757f3fSDimitry Andric 
1355f757f3fSDimitry Andric #else // _LIBCPP_CXX03_LANG
1365f757f3fSDimitry Andric 
1375f757f3fSDimitry Andric template <class _Callable>
1385f757f3fSDimitry Andric inline _LIBCPP_HIDE_FROM_ABI void call_once(once_flag& __flag, _Callable& __func) {
1395f757f3fSDimitry Andric   if (__libcpp_acquire_load(&__flag.__state_) != once_flag::_Complete) {
1405f757f3fSDimitry Andric     __call_once_param<_Callable> __p(__func);
1415f757f3fSDimitry Andric     std::__call_once(__flag.__state_, &__p, &__call_once_proxy<_Callable>);
1425f757f3fSDimitry Andric   }
1435f757f3fSDimitry Andric }
1445f757f3fSDimitry Andric 
1455f757f3fSDimitry Andric template <class _Callable>
1465f757f3fSDimitry Andric inline _LIBCPP_HIDE_FROM_ABI void call_once(once_flag& __flag, const _Callable& __func) {
1475f757f3fSDimitry Andric   if (__libcpp_acquire_load(&__flag.__state_) != once_flag::_Complete) {
1485f757f3fSDimitry Andric     __call_once_param<const _Callable> __p(__func);
1495f757f3fSDimitry Andric     std::__call_once(__flag.__state_, &__p, &__call_once_proxy<const _Callable>);
1505f757f3fSDimitry Andric   }
1515f757f3fSDimitry Andric }
1525f757f3fSDimitry Andric 
1535f757f3fSDimitry Andric #endif // _LIBCPP_CXX03_LANG
1545f757f3fSDimitry Andric 
1555f757f3fSDimitry Andric _LIBCPP_END_NAMESPACE_STD
1565f757f3fSDimitry Andric 
157*b3edf446SDimitry Andric _LIBCPP_POP_MACROS
158*b3edf446SDimitry Andric 
1595f757f3fSDimitry Andric #endif // _LIBCPP___MUTEX_ONCE_FLAG_H
160