//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include <__mutex/once_flag.h> #include <__utility/exception_guard.h> #ifndef _LIBCPP_HAS_NO_THREADS # include <__threading_support> #endif #include "include/atomic_support.h" _LIBCPP_BEGIN_NAMESPACE_STD // If dispatch_once_f ever handles C++ exceptions, and if one can get to it // without illegal macros (unexpected macros not beginning with _UpperCase or // __lowercase), and if it stops spinning waiting threads, then call_once should // call into dispatch_once_f instead of here. Relevant radar this code needs to // keep in sync with: 7741191. #ifndef _LIBCPP_HAS_NO_THREADS static constinit __libcpp_mutex_t mut = _LIBCPP_MUTEX_INITIALIZER; static constinit __libcpp_condvar_t cv = _LIBCPP_CONDVAR_INITIALIZER; #endif void __call_once(volatile once_flag::_State_type& flag, void* arg, void (*func)(void*)) { #if defined(_LIBCPP_HAS_NO_THREADS) if (flag == once_flag::_Unset) { auto guard = std::__make_exception_guard([&flag] { flag = once_flag::_Unset; }); flag = once_flag::_Pending; func(arg); flag = once_flag::_Complete; guard.__complete(); } #else // !_LIBCPP_HAS_NO_THREADS __libcpp_mutex_lock(&mut); while (flag == once_flag::_Pending) __libcpp_condvar_wait(&cv, &mut); if (flag == once_flag::_Unset) { auto guard = std::__make_exception_guard([&flag] { __libcpp_mutex_lock(&mut); __libcpp_relaxed_store(&flag, once_flag::_Unset); __libcpp_mutex_unlock(&mut); __libcpp_condvar_broadcast(&cv); }); __libcpp_relaxed_store(&flag, once_flag::_Pending); __libcpp_mutex_unlock(&mut); func(arg); __libcpp_mutex_lock(&mut); __libcpp_atomic_store(&flag, once_flag::_Complete, _AO_Release); __libcpp_mutex_unlock(&mut); __libcpp_condvar_broadcast(&cv); guard.__complete(); } else { __libcpp_mutex_unlock(&mut); } #endif // !_LIBCPP_HAS_NO_THREADS } _LIBCPP_END_NAMESPACE_STD