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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include <__mutex/once_flag.h> 10 #include <__utility/exception_guard.h> 11 12 #ifndef _LIBCPP_HAS_NO_THREADS 13 # include <__thread/support.h> 14 #endif 15 16 #include "include/atomic_support.h" 17 18 _LIBCPP_BEGIN_NAMESPACE_STD 19 20 // If dispatch_once_f ever handles C++ exceptions, and if one can get to it 21 // without illegal macros (unexpected macros not beginning with _UpperCase or 22 // __lowercase), and if it stops spinning waiting threads, then call_once should 23 // call into dispatch_once_f instead of here. Relevant radar this code needs to 24 // keep in sync with: 7741191. 25 26 #ifndef _LIBCPP_HAS_NO_THREADS 27 static constinit __libcpp_mutex_t mut = _LIBCPP_MUTEX_INITIALIZER; 28 static constinit __libcpp_condvar_t cv = _LIBCPP_CONDVAR_INITIALIZER; 29 #endif 30 31 void __call_once(volatile once_flag::_State_type& flag, void* arg, void (*func)(void*)) { 32 #if defined(_LIBCPP_HAS_NO_THREADS) 33 34 if (flag == once_flag::_Unset) { 35 auto guard = std::__make_exception_guard([&flag] { flag = once_flag::_Unset; }); 36 flag = once_flag::_Pending; 37 func(arg); 38 flag = once_flag::_Complete; 39 guard.__complete(); 40 } 41 42 #else // !_LIBCPP_HAS_NO_THREADS 43 44 __libcpp_mutex_lock(&mut); 45 while (flag == once_flag::_Pending) 46 __libcpp_condvar_wait(&cv, &mut); 47 if (flag == once_flag::_Unset) { 48 auto guard = std::__make_exception_guard([&flag] { 49 __libcpp_mutex_lock(&mut); 50 __libcpp_relaxed_store(&flag, once_flag::_Unset); 51 __libcpp_mutex_unlock(&mut); 52 __libcpp_condvar_broadcast(&cv); 53 }); 54 55 __libcpp_relaxed_store(&flag, once_flag::_Pending); 56 __libcpp_mutex_unlock(&mut); 57 func(arg); 58 __libcpp_mutex_lock(&mut); 59 __libcpp_atomic_store(&flag, once_flag::_Complete, _AO_Release); 60 __libcpp_mutex_unlock(&mut); 61 __libcpp_condvar_broadcast(&cv); 62 guard.__complete(); 63 } else { 64 __libcpp_mutex_unlock(&mut); 65 } 66 67 #endif // !_LIBCPP_HAS_NO_THREADS 68 } 69 70 _LIBCPP_END_NAMESPACE_STD 71