1 //===----------------------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include <__mutex/once_flag.h>
10 #include <__utility/exception_guard.h>
12 #if _LIBCPP_HAS_THREADS
13 # include <__thread/support.h>
16 #include "include/atomic_support.h"
18 _LIBCPP_BEGIN_NAMESPACE_STD
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.
26 #if _LIBCPP_HAS_THREADS
27 static constinit __libcpp_mutex_t mut
= _LIBCPP_MUTEX_INITIALIZER
;
28 static constinit __libcpp_condvar_t cv
= _LIBCPP_CONDVAR_INITIALIZER
;
31 void __call_once(volatile once_flag::_State_type
& flag
, void* arg
, void (*func
)(void*)) {
32 #if !_LIBCPP_HAS_THREADS
34 if (flag
== once_flag::_Unset
) {
35 auto guard
= std::__make_exception_guard([&flag
] { flag
= once_flag::_Unset
; });
36 flag
= once_flag::_Pending
;
38 flag
= once_flag::_Complete
;
42 #else // !_LIBCPP_HAS_THREADS
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
);
55 __libcpp_relaxed_store(&flag
, once_flag::_Pending
);
56 __libcpp_mutex_unlock(&mut
);
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
);
64 __libcpp_mutex_unlock(&mut
);
67 #endif // !_LIBCPP_HAS_THREADS
70 _LIBCPP_END_NAMESPACE_STD