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 <__threading_support> 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 27static constinit __libcpp_mutex_t mut = _LIBCPP_MUTEX_INITIALIZER; 28static constinit __libcpp_condvar_t cv = _LIBCPP_CONDVAR_INITIALIZER; 29#endif 30 31void __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