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