1*c05d8e5dSAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
2*c05d8e5dSAndroid Build Coastguard Worker //
3*c05d8e5dSAndroid Build Coastguard Worker // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*c05d8e5dSAndroid Build Coastguard Worker // See https://llvm.org/LICENSE.txt for license information.
5*c05d8e5dSAndroid Build Coastguard Worker // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*c05d8e5dSAndroid Build Coastguard Worker //
7*c05d8e5dSAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
8*c05d8e5dSAndroid Build Coastguard Worker #ifndef LIBCXXABI_SRC_INCLUDE_CXA_GUARD_IMPL_H
9*c05d8e5dSAndroid Build Coastguard Worker #define LIBCXXABI_SRC_INCLUDE_CXA_GUARD_IMPL_H
10*c05d8e5dSAndroid Build Coastguard Worker
11*c05d8e5dSAndroid Build Coastguard Worker /* cxa_guard_impl.h - Implements the C++ runtime support for function local
12*c05d8e5dSAndroid Build Coastguard Worker * static guards.
13*c05d8e5dSAndroid Build Coastguard Worker * The layout of the guard object is the same across ARM and Itanium.
14*c05d8e5dSAndroid Build Coastguard Worker *
15*c05d8e5dSAndroid Build Coastguard Worker * The first "guard byte" (which is checked by the compiler) is set only upon
16*c05d8e5dSAndroid Build Coastguard Worker * the completion of cxa release.
17*c05d8e5dSAndroid Build Coastguard Worker *
18*c05d8e5dSAndroid Build Coastguard Worker * The second "init byte" does the rest of the bookkeeping. It tracks if
19*c05d8e5dSAndroid Build Coastguard Worker * initialization is complete or pending, and if there are waiting threads.
20*c05d8e5dSAndroid Build Coastguard Worker *
21*c05d8e5dSAndroid Build Coastguard Worker * If the guard variable is 64-bits and the platforms supplies a 32-bit thread
22*c05d8e5dSAndroid Build Coastguard Worker * identifier, it is used to detect recursive initialization. The thread ID of
23*c05d8e5dSAndroid Build Coastguard Worker * the thread currently performing initialization is stored in the second word.
24*c05d8e5dSAndroid Build Coastguard Worker *
25*c05d8e5dSAndroid Build Coastguard Worker * Guard Object Layout:
26*c05d8e5dSAndroid Build Coastguard Worker * -------------------------------------------------------------------------
27*c05d8e5dSAndroid Build Coastguard Worker * |a: guard byte | a+1: init byte | a+2 : unused ... | a+4: thread-id ... |
28*c05d8e5dSAndroid Build Coastguard Worker * ------------------------------------------------------------------------
29*c05d8e5dSAndroid Build Coastguard Worker *
30*c05d8e5dSAndroid Build Coastguard Worker * Access Protocol:
31*c05d8e5dSAndroid Build Coastguard Worker * For each implementation the guard byte is checked and set before accessing
32*c05d8e5dSAndroid Build Coastguard Worker * the init byte.
33*c05d8e5dSAndroid Build Coastguard Worker *
34*c05d8e5dSAndroid Build Coastguard Worker * Overall Design:
35*c05d8e5dSAndroid Build Coastguard Worker * The implementation was designed to allow each implementation to be tested
36*c05d8e5dSAndroid Build Coastguard Worker * independent of the C++ runtime or platform support.
37*c05d8e5dSAndroid Build Coastguard Worker *
38*c05d8e5dSAndroid Build Coastguard Worker */
39*c05d8e5dSAndroid Build Coastguard Worker
40*c05d8e5dSAndroid Build Coastguard Worker #include "__cxxabi_config.h"
41*c05d8e5dSAndroid Build Coastguard Worker #include "include/atomic_support.h"
42*c05d8e5dSAndroid Build Coastguard Worker #include <unistd.h>
43*c05d8e5dSAndroid Build Coastguard Worker #include <sys/types.h>
44*c05d8e5dSAndroid Build Coastguard Worker // Android Trusty: sys/syscall.h tries to include bits/syscall.h, which is
45*c05d8e5dSAndroid Build Coastguard Worker // missing. Trusty seems to define _LIBCXXABI_HAS_NO_THREADS, and gettid isn't
46*c05d8e5dSAndroid Build Coastguard Worker // needed in that case, so skip sys/syscall.h.
47*c05d8e5dSAndroid Build Coastguard Worker #if defined(__has_include) && !defined(_LIBCXXABI_HAS_NO_THREADS)
48*c05d8e5dSAndroid Build Coastguard Worker # if __has_include(<sys/syscall.h>)
49*c05d8e5dSAndroid Build Coastguard Worker # include <sys/syscall.h>
50*c05d8e5dSAndroid Build Coastguard Worker # endif
51*c05d8e5dSAndroid Build Coastguard Worker #endif
52*c05d8e5dSAndroid Build Coastguard Worker
53*c05d8e5dSAndroid Build Coastguard Worker #include <stdlib.h>
54*c05d8e5dSAndroid Build Coastguard Worker #include <__threading_support>
55*c05d8e5dSAndroid Build Coastguard Worker
56*c05d8e5dSAndroid Build Coastguard Worker // To make testing possible, this header is included from both cxa_guard.cpp
57*c05d8e5dSAndroid Build Coastguard Worker // and a number of tests.
58*c05d8e5dSAndroid Build Coastguard Worker //
59*c05d8e5dSAndroid Build Coastguard Worker // For this reason we place everything in an anonymous namespace -- even though
60*c05d8e5dSAndroid Build Coastguard Worker // we're in a header. We want the actual implementation and the tests to have
61*c05d8e5dSAndroid Build Coastguard Worker // unique definitions of the types in this header (since the tests may depend
62*c05d8e5dSAndroid Build Coastguard Worker // on function local statics).
63*c05d8e5dSAndroid Build Coastguard Worker //
64*c05d8e5dSAndroid Build Coastguard Worker // To enforce this either `BUILDING_CXA_GUARD` or `TESTING_CXA_GUARD` must be
65*c05d8e5dSAndroid Build Coastguard Worker // defined when including this file. Only `src/cxa_guard.cpp` should define
66*c05d8e5dSAndroid Build Coastguard Worker // the former.
67*c05d8e5dSAndroid Build Coastguard Worker #ifdef BUILDING_CXA_GUARD
68*c05d8e5dSAndroid Build Coastguard Worker # include "abort_message.h"
69*c05d8e5dSAndroid Build Coastguard Worker # define ABORT_WITH_MESSAGE(...) ::abort_message(__VA_ARGS__)
70*c05d8e5dSAndroid Build Coastguard Worker #elif defined(TESTING_CXA_GUARD)
71*c05d8e5dSAndroid Build Coastguard Worker # define ABORT_WITH_MESSAGE(...) ::abort()
72*c05d8e5dSAndroid Build Coastguard Worker #else
73*c05d8e5dSAndroid Build Coastguard Worker # error "Either BUILDING_CXA_GUARD or TESTING_CXA_GUARD must be defined"
74*c05d8e5dSAndroid Build Coastguard Worker #endif
75*c05d8e5dSAndroid Build Coastguard Worker
76*c05d8e5dSAndroid Build Coastguard Worker #if __has_feature(thread_sanitizer)
77*c05d8e5dSAndroid Build Coastguard Worker extern "C" void __tsan_acquire(void*);
78*c05d8e5dSAndroid Build Coastguard Worker extern "C" void __tsan_release(void*);
79*c05d8e5dSAndroid Build Coastguard Worker #else
80*c05d8e5dSAndroid Build Coastguard Worker #define __tsan_acquire(addr) ((void)0)
81*c05d8e5dSAndroid Build Coastguard Worker #define __tsan_release(addr) ((void)0)
82*c05d8e5dSAndroid Build Coastguard Worker #endif
83*c05d8e5dSAndroid Build Coastguard Worker
84*c05d8e5dSAndroid Build Coastguard Worker namespace __cxxabiv1 {
85*c05d8e5dSAndroid Build Coastguard Worker // Use an anonymous namespace to ensure that the tests and actual implementation
86*c05d8e5dSAndroid Build Coastguard Worker // have unique definitions of these symbols.
87*c05d8e5dSAndroid Build Coastguard Worker namespace {
88*c05d8e5dSAndroid Build Coastguard Worker
89*c05d8e5dSAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
90*c05d8e5dSAndroid Build Coastguard Worker // Misc Utilities
91*c05d8e5dSAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
92*c05d8e5dSAndroid Build Coastguard Worker
93*c05d8e5dSAndroid Build Coastguard Worker template <class T, T(*Init)()>
94*c05d8e5dSAndroid Build Coastguard Worker struct LazyValue {
LazyValueLazyValue95*c05d8e5dSAndroid Build Coastguard Worker LazyValue() : is_init(false) {}
96*c05d8e5dSAndroid Build Coastguard Worker
getLazyValue97*c05d8e5dSAndroid Build Coastguard Worker T& get() {
98*c05d8e5dSAndroid Build Coastguard Worker if (!is_init) {
99*c05d8e5dSAndroid Build Coastguard Worker value = Init();
100*c05d8e5dSAndroid Build Coastguard Worker is_init = true;
101*c05d8e5dSAndroid Build Coastguard Worker }
102*c05d8e5dSAndroid Build Coastguard Worker return value;
103*c05d8e5dSAndroid Build Coastguard Worker }
104*c05d8e5dSAndroid Build Coastguard Worker private:
105*c05d8e5dSAndroid Build Coastguard Worker T value;
106*c05d8e5dSAndroid Build Coastguard Worker bool is_init = false;
107*c05d8e5dSAndroid Build Coastguard Worker };
108*c05d8e5dSAndroid Build Coastguard Worker
109*c05d8e5dSAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
110*c05d8e5dSAndroid Build Coastguard Worker // PlatformGetThreadID
111*c05d8e5dSAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
112*c05d8e5dSAndroid Build Coastguard Worker
113*c05d8e5dSAndroid Build Coastguard Worker #if defined(__APPLE__) && defined(_LIBCPP_HAS_THREAD_API_PTHREAD)
PlatformThreadID()114*c05d8e5dSAndroid Build Coastguard Worker uint32_t PlatformThreadID() {
115*c05d8e5dSAndroid Build Coastguard Worker static_assert(sizeof(mach_port_t) == sizeof(uint32_t), "");
116*c05d8e5dSAndroid Build Coastguard Worker return static_cast<uint32_t>(
117*c05d8e5dSAndroid Build Coastguard Worker pthread_mach_thread_np(std::__libcpp_thread_get_current_id()));
118*c05d8e5dSAndroid Build Coastguard Worker }
119*c05d8e5dSAndroid Build Coastguard Worker #elif defined(SYS_gettid) && defined(_LIBCPP_HAS_THREAD_API_PTHREAD) && \
120*c05d8e5dSAndroid Build Coastguard Worker !defined(__BIONIC__)
121*c05d8e5dSAndroid Build Coastguard Worker // Bionic: Disable the SYS_gettid feature for now. Some processes on Android
122*c05d8e5dSAndroid Build Coastguard Worker // block SYS_gettid using seccomp.
PlatformThreadID()123*c05d8e5dSAndroid Build Coastguard Worker uint32_t PlatformThreadID() {
124*c05d8e5dSAndroid Build Coastguard Worker static_assert(sizeof(pid_t) == sizeof(uint32_t), "");
125*c05d8e5dSAndroid Build Coastguard Worker return static_cast<uint32_t>(syscall(SYS_gettid));
126*c05d8e5dSAndroid Build Coastguard Worker }
127*c05d8e5dSAndroid Build Coastguard Worker #else
128*c05d8e5dSAndroid Build Coastguard Worker constexpr uint32_t (*PlatformThreadID)() = nullptr;
129*c05d8e5dSAndroid Build Coastguard Worker #endif
130*c05d8e5dSAndroid Build Coastguard Worker
131*c05d8e5dSAndroid Build Coastguard Worker
PlatformSupportsThreadID()132*c05d8e5dSAndroid Build Coastguard Worker constexpr bool PlatformSupportsThreadID() {
133*c05d8e5dSAndroid Build Coastguard Worker #ifdef __clang__
134*c05d8e5dSAndroid Build Coastguard Worker #pragma clang diagnostic push
135*c05d8e5dSAndroid Build Coastguard Worker #pragma clang diagnostic ignored "-Wtautological-pointer-compare"
136*c05d8e5dSAndroid Build Coastguard Worker #endif
137*c05d8e5dSAndroid Build Coastguard Worker return +PlatformThreadID != nullptr;
138*c05d8e5dSAndroid Build Coastguard Worker #ifdef __clang__
139*c05d8e5dSAndroid Build Coastguard Worker #pragma clang diagnostic pop
140*c05d8e5dSAndroid Build Coastguard Worker #endif
141*c05d8e5dSAndroid Build Coastguard Worker }
142*c05d8e5dSAndroid Build Coastguard Worker
143*c05d8e5dSAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
144*c05d8e5dSAndroid Build Coastguard Worker // GuardBase
145*c05d8e5dSAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
146*c05d8e5dSAndroid Build Coastguard Worker
147*c05d8e5dSAndroid Build Coastguard Worker enum class AcquireResult {
148*c05d8e5dSAndroid Build Coastguard Worker INIT_IS_DONE,
149*c05d8e5dSAndroid Build Coastguard Worker INIT_IS_PENDING,
150*c05d8e5dSAndroid Build Coastguard Worker };
151*c05d8e5dSAndroid Build Coastguard Worker constexpr AcquireResult INIT_IS_DONE = AcquireResult::INIT_IS_DONE;
152*c05d8e5dSAndroid Build Coastguard Worker constexpr AcquireResult INIT_IS_PENDING = AcquireResult::INIT_IS_PENDING;
153*c05d8e5dSAndroid Build Coastguard Worker
154*c05d8e5dSAndroid Build Coastguard Worker static constexpr uint8_t UNSET = 0;
155*c05d8e5dSAndroid Build Coastguard Worker static constexpr uint8_t COMPLETE_BIT = (1 << 0);
156*c05d8e5dSAndroid Build Coastguard Worker static constexpr uint8_t PENDING_BIT = (1 << 1);
157*c05d8e5dSAndroid Build Coastguard Worker static constexpr uint8_t WAITING_BIT = (1 << 2);
158*c05d8e5dSAndroid Build Coastguard Worker
159*c05d8e5dSAndroid Build Coastguard Worker template <class Derived>
160*c05d8e5dSAndroid Build Coastguard Worker struct GuardObject {
161*c05d8e5dSAndroid Build Coastguard Worker GuardObject() = delete;
162*c05d8e5dSAndroid Build Coastguard Worker GuardObject(GuardObject const&) = delete;
163*c05d8e5dSAndroid Build Coastguard Worker GuardObject& operator=(GuardObject const&) = delete;
164*c05d8e5dSAndroid Build Coastguard Worker
GuardObjectGuardObject165*c05d8e5dSAndroid Build Coastguard Worker explicit GuardObject(uint32_t* g)
166*c05d8e5dSAndroid Build Coastguard Worker : base_address(g), guard_byte_address(reinterpret_cast<uint8_t*>(g)),
167*c05d8e5dSAndroid Build Coastguard Worker init_byte_address(reinterpret_cast<uint8_t*>(g) + 1),
168*c05d8e5dSAndroid Build Coastguard Worker thread_id_address(nullptr) {}
169*c05d8e5dSAndroid Build Coastguard Worker
GuardObjectGuardObject170*c05d8e5dSAndroid Build Coastguard Worker explicit GuardObject(uint64_t* g)
171*c05d8e5dSAndroid Build Coastguard Worker : base_address(g), guard_byte_address(reinterpret_cast<uint8_t*>(g)),
172*c05d8e5dSAndroid Build Coastguard Worker init_byte_address(reinterpret_cast<uint8_t*>(g) + 1),
173*c05d8e5dSAndroid Build Coastguard Worker thread_id_address(reinterpret_cast<uint32_t*>(g) + 1) {}
174*c05d8e5dSAndroid Build Coastguard Worker
175*c05d8e5dSAndroid Build Coastguard Worker public:
176*c05d8e5dSAndroid Build Coastguard Worker /// Implements __cxa_guard_acquire
cxa_guard_acquireGuardObject177*c05d8e5dSAndroid Build Coastguard Worker AcquireResult cxa_guard_acquire() {
178*c05d8e5dSAndroid Build Coastguard Worker AtomicInt<uint8_t> guard_byte(guard_byte_address);
179*c05d8e5dSAndroid Build Coastguard Worker if (guard_byte.load(std::_AO_Acquire) != UNSET)
180*c05d8e5dSAndroid Build Coastguard Worker return INIT_IS_DONE;
181*c05d8e5dSAndroid Build Coastguard Worker return derived()->acquire_init_byte();
182*c05d8e5dSAndroid Build Coastguard Worker }
183*c05d8e5dSAndroid Build Coastguard Worker
184*c05d8e5dSAndroid Build Coastguard Worker /// Implements __cxa_guard_release
cxa_guard_releaseGuardObject185*c05d8e5dSAndroid Build Coastguard Worker void cxa_guard_release() {
186*c05d8e5dSAndroid Build Coastguard Worker AtomicInt<uint8_t> guard_byte(guard_byte_address);
187*c05d8e5dSAndroid Build Coastguard Worker // Store complete first, so that when release wakes other folks, they see
188*c05d8e5dSAndroid Build Coastguard Worker // it as having been completed.
189*c05d8e5dSAndroid Build Coastguard Worker guard_byte.store(COMPLETE_BIT, std::_AO_Release);
190*c05d8e5dSAndroid Build Coastguard Worker derived()->release_init_byte();
191*c05d8e5dSAndroid Build Coastguard Worker }
192*c05d8e5dSAndroid Build Coastguard Worker
193*c05d8e5dSAndroid Build Coastguard Worker /// Implements __cxa_guard_abort
cxa_guard_abortGuardObject194*c05d8e5dSAndroid Build Coastguard Worker void cxa_guard_abort() { derived()->abort_init_byte(); }
195*c05d8e5dSAndroid Build Coastguard Worker
196*c05d8e5dSAndroid Build Coastguard Worker public:
197*c05d8e5dSAndroid Build Coastguard Worker /// base_address - the address of the original guard object.
198*c05d8e5dSAndroid Build Coastguard Worker void* const base_address;
199*c05d8e5dSAndroid Build Coastguard Worker /// The address of the guord byte at offset 0.
200*c05d8e5dSAndroid Build Coastguard Worker uint8_t* const guard_byte_address;
201*c05d8e5dSAndroid Build Coastguard Worker /// The address of the byte used by the implementation during initialization.
202*c05d8e5dSAndroid Build Coastguard Worker uint8_t* const init_byte_address;
203*c05d8e5dSAndroid Build Coastguard Worker /// An optional address storing an identifier for the thread performing initialization.
204*c05d8e5dSAndroid Build Coastguard Worker /// It's used to detect recursive initialization.
205*c05d8e5dSAndroid Build Coastguard Worker uint32_t* const thread_id_address;
206*c05d8e5dSAndroid Build Coastguard Worker
207*c05d8e5dSAndroid Build Coastguard Worker private:
derivedGuardObject208*c05d8e5dSAndroid Build Coastguard Worker Derived* derived() { return static_cast<Derived*>(this); }
209*c05d8e5dSAndroid Build Coastguard Worker };
210*c05d8e5dSAndroid Build Coastguard Worker
211*c05d8e5dSAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
212*c05d8e5dSAndroid Build Coastguard Worker // Single Threaded Implementation
213*c05d8e5dSAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
214*c05d8e5dSAndroid Build Coastguard Worker
215*c05d8e5dSAndroid Build Coastguard Worker struct InitByteNoThreads : GuardObject<InitByteNoThreads> {
216*c05d8e5dSAndroid Build Coastguard Worker using GuardObject::GuardObject;
217*c05d8e5dSAndroid Build Coastguard Worker
acquire_init_byteInitByteNoThreads218*c05d8e5dSAndroid Build Coastguard Worker AcquireResult acquire_init_byte() {
219*c05d8e5dSAndroid Build Coastguard Worker if (*init_byte_address == COMPLETE_BIT)
220*c05d8e5dSAndroid Build Coastguard Worker return INIT_IS_DONE;
221*c05d8e5dSAndroid Build Coastguard Worker if (*init_byte_address & PENDING_BIT)
222*c05d8e5dSAndroid Build Coastguard Worker ABORT_WITH_MESSAGE("__cxa_guard_acquire detected recursive initialization");
223*c05d8e5dSAndroid Build Coastguard Worker *init_byte_address = PENDING_BIT;
224*c05d8e5dSAndroid Build Coastguard Worker return INIT_IS_PENDING;
225*c05d8e5dSAndroid Build Coastguard Worker }
226*c05d8e5dSAndroid Build Coastguard Worker
release_init_byteInitByteNoThreads227*c05d8e5dSAndroid Build Coastguard Worker void release_init_byte() { *init_byte_address = COMPLETE_BIT; }
abort_init_byteInitByteNoThreads228*c05d8e5dSAndroid Build Coastguard Worker void abort_init_byte() { *init_byte_address = UNSET; }
229*c05d8e5dSAndroid Build Coastguard Worker };
230*c05d8e5dSAndroid Build Coastguard Worker
231*c05d8e5dSAndroid Build Coastguard Worker
232*c05d8e5dSAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
233*c05d8e5dSAndroid Build Coastguard Worker // Global Mutex Implementation
234*c05d8e5dSAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
235*c05d8e5dSAndroid Build Coastguard Worker
236*c05d8e5dSAndroid Build Coastguard Worker struct LibcppMutex;
237*c05d8e5dSAndroid Build Coastguard Worker struct LibcppCondVar;
238*c05d8e5dSAndroid Build Coastguard Worker
239*c05d8e5dSAndroid Build Coastguard Worker #ifndef _LIBCXXABI_HAS_NO_THREADS
240*c05d8e5dSAndroid Build Coastguard Worker struct LibcppMutex {
241*c05d8e5dSAndroid Build Coastguard Worker LibcppMutex() = default;
242*c05d8e5dSAndroid Build Coastguard Worker LibcppMutex(LibcppMutex const&) = delete;
243*c05d8e5dSAndroid Build Coastguard Worker LibcppMutex& operator=(LibcppMutex const&) = delete;
244*c05d8e5dSAndroid Build Coastguard Worker
lockLibcppMutex245*c05d8e5dSAndroid Build Coastguard Worker bool lock() { return std::__libcpp_mutex_lock(&mutex); }
unlockLibcppMutex246*c05d8e5dSAndroid Build Coastguard Worker bool unlock() { return std::__libcpp_mutex_unlock(&mutex); }
247*c05d8e5dSAndroid Build Coastguard Worker
248*c05d8e5dSAndroid Build Coastguard Worker private:
249*c05d8e5dSAndroid Build Coastguard Worker friend struct LibcppCondVar;
250*c05d8e5dSAndroid Build Coastguard Worker std::__libcpp_mutex_t mutex = _LIBCPP_MUTEX_INITIALIZER;
251*c05d8e5dSAndroid Build Coastguard Worker };
252*c05d8e5dSAndroid Build Coastguard Worker
253*c05d8e5dSAndroid Build Coastguard Worker struct LibcppCondVar {
254*c05d8e5dSAndroid Build Coastguard Worker LibcppCondVar() = default;
255*c05d8e5dSAndroid Build Coastguard Worker LibcppCondVar(LibcppCondVar const&) = delete;
256*c05d8e5dSAndroid Build Coastguard Worker LibcppCondVar& operator=(LibcppCondVar const&) = delete;
257*c05d8e5dSAndroid Build Coastguard Worker
waitLibcppCondVar258*c05d8e5dSAndroid Build Coastguard Worker bool wait(LibcppMutex& mut) {
259*c05d8e5dSAndroid Build Coastguard Worker return std::__libcpp_condvar_wait(&cond, &mut.mutex);
260*c05d8e5dSAndroid Build Coastguard Worker }
broadcastLibcppCondVar261*c05d8e5dSAndroid Build Coastguard Worker bool broadcast() { return std::__libcpp_condvar_broadcast(&cond); }
262*c05d8e5dSAndroid Build Coastguard Worker
263*c05d8e5dSAndroid Build Coastguard Worker private:
264*c05d8e5dSAndroid Build Coastguard Worker std::__libcpp_condvar_t cond = _LIBCPP_CONDVAR_INITIALIZER;
265*c05d8e5dSAndroid Build Coastguard Worker };
266*c05d8e5dSAndroid Build Coastguard Worker #else
267*c05d8e5dSAndroid Build Coastguard Worker struct LibcppMutex {};
268*c05d8e5dSAndroid Build Coastguard Worker struct LibcppCondVar {};
269*c05d8e5dSAndroid Build Coastguard Worker #endif // !defined(_LIBCXXABI_HAS_NO_THREADS)
270*c05d8e5dSAndroid Build Coastguard Worker
271*c05d8e5dSAndroid Build Coastguard Worker
272*c05d8e5dSAndroid Build Coastguard Worker template <class Mutex, class CondVar, Mutex& global_mutex, CondVar& global_cond,
273*c05d8e5dSAndroid Build Coastguard Worker uint32_t (*GetThreadID)() = PlatformThreadID>
274*c05d8e5dSAndroid Build Coastguard Worker struct InitByteGlobalMutex
275*c05d8e5dSAndroid Build Coastguard Worker : GuardObject<InitByteGlobalMutex<Mutex, CondVar, global_mutex, global_cond,
276*c05d8e5dSAndroid Build Coastguard Worker GetThreadID>> {
277*c05d8e5dSAndroid Build Coastguard Worker
278*c05d8e5dSAndroid Build Coastguard Worker using BaseT = typename InitByteGlobalMutex::GuardObject;
279*c05d8e5dSAndroid Build Coastguard Worker using BaseT::BaseT;
280*c05d8e5dSAndroid Build Coastguard Worker
InitByteGlobalMutexInitByteGlobalMutex281*c05d8e5dSAndroid Build Coastguard Worker explicit InitByteGlobalMutex(uint32_t *g)
282*c05d8e5dSAndroid Build Coastguard Worker : BaseT(g), has_thread_id_support(false) {}
InitByteGlobalMutexInitByteGlobalMutex283*c05d8e5dSAndroid Build Coastguard Worker explicit InitByteGlobalMutex(uint64_t *g)
284*c05d8e5dSAndroid Build Coastguard Worker : BaseT(g), has_thread_id_support(PlatformSupportsThreadID()) {}
285*c05d8e5dSAndroid Build Coastguard Worker
286*c05d8e5dSAndroid Build Coastguard Worker public:
acquire_init_byteInitByteGlobalMutex287*c05d8e5dSAndroid Build Coastguard Worker AcquireResult acquire_init_byte() {
288*c05d8e5dSAndroid Build Coastguard Worker LockGuard g("__cxa_guard_acquire");
289*c05d8e5dSAndroid Build Coastguard Worker // Check for possible recursive initialization.
290*c05d8e5dSAndroid Build Coastguard Worker if (has_thread_id_support && (*init_byte_address & PENDING_BIT)) {
291*c05d8e5dSAndroid Build Coastguard Worker if (*thread_id_address == current_thread_id.get())
292*c05d8e5dSAndroid Build Coastguard Worker ABORT_WITH_MESSAGE("__cxa_guard_acquire detected recursive initialization");
293*c05d8e5dSAndroid Build Coastguard Worker }
294*c05d8e5dSAndroid Build Coastguard Worker
295*c05d8e5dSAndroid Build Coastguard Worker // Wait until the pending bit is not set.
296*c05d8e5dSAndroid Build Coastguard Worker while (*init_byte_address & PENDING_BIT) {
297*c05d8e5dSAndroid Build Coastguard Worker *init_byte_address |= WAITING_BIT;
298*c05d8e5dSAndroid Build Coastguard Worker global_cond.wait(global_mutex);
299*c05d8e5dSAndroid Build Coastguard Worker }
300*c05d8e5dSAndroid Build Coastguard Worker
301*c05d8e5dSAndroid Build Coastguard Worker if (*init_byte_address == COMPLETE_BIT)
302*c05d8e5dSAndroid Build Coastguard Worker return INIT_IS_DONE;
303*c05d8e5dSAndroid Build Coastguard Worker
304*c05d8e5dSAndroid Build Coastguard Worker if (has_thread_id_support)
305*c05d8e5dSAndroid Build Coastguard Worker *thread_id_address = current_thread_id.get();
306*c05d8e5dSAndroid Build Coastguard Worker
307*c05d8e5dSAndroid Build Coastguard Worker *init_byte_address = PENDING_BIT;
308*c05d8e5dSAndroid Build Coastguard Worker return INIT_IS_PENDING;
309*c05d8e5dSAndroid Build Coastguard Worker }
310*c05d8e5dSAndroid Build Coastguard Worker
release_init_byteInitByteGlobalMutex311*c05d8e5dSAndroid Build Coastguard Worker void release_init_byte() {
312*c05d8e5dSAndroid Build Coastguard Worker bool has_waiting;
313*c05d8e5dSAndroid Build Coastguard Worker {
314*c05d8e5dSAndroid Build Coastguard Worker LockGuard g("__cxa_guard_release");
315*c05d8e5dSAndroid Build Coastguard Worker has_waiting = *init_byte_address & WAITING_BIT;
316*c05d8e5dSAndroid Build Coastguard Worker *init_byte_address = COMPLETE_BIT;
317*c05d8e5dSAndroid Build Coastguard Worker }
318*c05d8e5dSAndroid Build Coastguard Worker if (has_waiting) {
319*c05d8e5dSAndroid Build Coastguard Worker if (global_cond.broadcast()) {
320*c05d8e5dSAndroid Build Coastguard Worker ABORT_WITH_MESSAGE("%s failed to broadcast", "__cxa_guard_release");
321*c05d8e5dSAndroid Build Coastguard Worker }
322*c05d8e5dSAndroid Build Coastguard Worker }
323*c05d8e5dSAndroid Build Coastguard Worker }
324*c05d8e5dSAndroid Build Coastguard Worker
abort_init_byteInitByteGlobalMutex325*c05d8e5dSAndroid Build Coastguard Worker void abort_init_byte() {
326*c05d8e5dSAndroid Build Coastguard Worker bool has_waiting;
327*c05d8e5dSAndroid Build Coastguard Worker {
328*c05d8e5dSAndroid Build Coastguard Worker LockGuard g("__cxa_guard_abort");
329*c05d8e5dSAndroid Build Coastguard Worker if (has_thread_id_support)
330*c05d8e5dSAndroid Build Coastguard Worker *thread_id_address = 0;
331*c05d8e5dSAndroid Build Coastguard Worker has_waiting = *init_byte_address & WAITING_BIT;
332*c05d8e5dSAndroid Build Coastguard Worker *init_byte_address = UNSET;
333*c05d8e5dSAndroid Build Coastguard Worker }
334*c05d8e5dSAndroid Build Coastguard Worker if (has_waiting) {
335*c05d8e5dSAndroid Build Coastguard Worker if (global_cond.broadcast()) {
336*c05d8e5dSAndroid Build Coastguard Worker ABORT_WITH_MESSAGE("%s failed to broadcast", "__cxa_guard_abort");
337*c05d8e5dSAndroid Build Coastguard Worker }
338*c05d8e5dSAndroid Build Coastguard Worker }
339*c05d8e5dSAndroid Build Coastguard Worker }
340*c05d8e5dSAndroid Build Coastguard Worker
341*c05d8e5dSAndroid Build Coastguard Worker private:
342*c05d8e5dSAndroid Build Coastguard Worker using BaseT::init_byte_address;
343*c05d8e5dSAndroid Build Coastguard Worker using BaseT::thread_id_address;
344*c05d8e5dSAndroid Build Coastguard Worker const bool has_thread_id_support;
345*c05d8e5dSAndroid Build Coastguard Worker LazyValue<uint32_t, GetThreadID> current_thread_id;
346*c05d8e5dSAndroid Build Coastguard Worker
347*c05d8e5dSAndroid Build Coastguard Worker private:
348*c05d8e5dSAndroid Build Coastguard Worker struct LockGuard {
349*c05d8e5dSAndroid Build Coastguard Worker LockGuard() = delete;
350*c05d8e5dSAndroid Build Coastguard Worker LockGuard(LockGuard const&) = delete;
351*c05d8e5dSAndroid Build Coastguard Worker LockGuard& operator=(LockGuard const&) = delete;
352*c05d8e5dSAndroid Build Coastguard Worker
LockGuardInitByteGlobalMutex::LockGuard353*c05d8e5dSAndroid Build Coastguard Worker explicit LockGuard(const char* calling_func)
354*c05d8e5dSAndroid Build Coastguard Worker : calling_func(calling_func) {
355*c05d8e5dSAndroid Build Coastguard Worker if (global_mutex.lock())
356*c05d8e5dSAndroid Build Coastguard Worker ABORT_WITH_MESSAGE("%s failed to acquire mutex", calling_func);
357*c05d8e5dSAndroid Build Coastguard Worker }
358*c05d8e5dSAndroid Build Coastguard Worker
~LockGuardInitByteGlobalMutex::LockGuard359*c05d8e5dSAndroid Build Coastguard Worker ~LockGuard() {
360*c05d8e5dSAndroid Build Coastguard Worker if (global_mutex.unlock())
361*c05d8e5dSAndroid Build Coastguard Worker ABORT_WITH_MESSAGE("%s failed to release mutex", calling_func);
362*c05d8e5dSAndroid Build Coastguard Worker }
363*c05d8e5dSAndroid Build Coastguard Worker
364*c05d8e5dSAndroid Build Coastguard Worker private:
365*c05d8e5dSAndroid Build Coastguard Worker const char* const calling_func;
366*c05d8e5dSAndroid Build Coastguard Worker };
367*c05d8e5dSAndroid Build Coastguard Worker };
368*c05d8e5dSAndroid Build Coastguard Worker
369*c05d8e5dSAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
370*c05d8e5dSAndroid Build Coastguard Worker // Futex Implementation
371*c05d8e5dSAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
372*c05d8e5dSAndroid Build Coastguard Worker
373*c05d8e5dSAndroid Build Coastguard Worker #if defined(SYS_futex)
PlatformFutexWait(int * addr,int expect)374*c05d8e5dSAndroid Build Coastguard Worker void PlatformFutexWait(int* addr, int expect) {
375*c05d8e5dSAndroid Build Coastguard Worker constexpr int WAIT = 0;
376*c05d8e5dSAndroid Build Coastguard Worker syscall(SYS_futex, addr, WAIT, expect, 0);
377*c05d8e5dSAndroid Build Coastguard Worker __tsan_acquire(addr);
378*c05d8e5dSAndroid Build Coastguard Worker }
PlatformFutexWake(int * addr)379*c05d8e5dSAndroid Build Coastguard Worker void PlatformFutexWake(int* addr) {
380*c05d8e5dSAndroid Build Coastguard Worker constexpr int WAKE = 1;
381*c05d8e5dSAndroid Build Coastguard Worker __tsan_release(addr);
382*c05d8e5dSAndroid Build Coastguard Worker syscall(SYS_futex, addr, WAKE, INT_MAX);
383*c05d8e5dSAndroid Build Coastguard Worker }
384*c05d8e5dSAndroid Build Coastguard Worker #else
385*c05d8e5dSAndroid Build Coastguard Worker constexpr void (*PlatformFutexWait)(int*, int) = nullptr;
386*c05d8e5dSAndroid Build Coastguard Worker constexpr void (*PlatformFutexWake)(int*) = nullptr;
387*c05d8e5dSAndroid Build Coastguard Worker #endif
388*c05d8e5dSAndroid Build Coastguard Worker
PlatformSupportsFutex()389*c05d8e5dSAndroid Build Coastguard Worker constexpr bool PlatformSupportsFutex() {
390*c05d8e5dSAndroid Build Coastguard Worker #ifdef __clang__
391*c05d8e5dSAndroid Build Coastguard Worker #pragma clang diagnostic push
392*c05d8e5dSAndroid Build Coastguard Worker #pragma clang diagnostic ignored "-Wtautological-pointer-compare"
393*c05d8e5dSAndroid Build Coastguard Worker #endif
394*c05d8e5dSAndroid Build Coastguard Worker return +PlatformFutexWait != nullptr;
395*c05d8e5dSAndroid Build Coastguard Worker #ifdef __clang__
396*c05d8e5dSAndroid Build Coastguard Worker #pragma clang diagnostic pop
397*c05d8e5dSAndroid Build Coastguard Worker #endif
398*c05d8e5dSAndroid Build Coastguard Worker }
399*c05d8e5dSAndroid Build Coastguard Worker
400*c05d8e5dSAndroid Build Coastguard Worker /// InitByteFutex - Manages initialization using atomics and the futex syscall
401*c05d8e5dSAndroid Build Coastguard Worker /// for waiting and waking.
402*c05d8e5dSAndroid Build Coastguard Worker template <void (*Wait)(int*, int) = PlatformFutexWait,
403*c05d8e5dSAndroid Build Coastguard Worker void (*Wake)(int*) = PlatformFutexWake,
404*c05d8e5dSAndroid Build Coastguard Worker uint32_t (*GetThreadIDArg)() = PlatformThreadID>
405*c05d8e5dSAndroid Build Coastguard Worker struct InitByteFutex : GuardObject<InitByteFutex<Wait, Wake, GetThreadIDArg>> {
406*c05d8e5dSAndroid Build Coastguard Worker using BaseT = typename InitByteFutex::GuardObject;
407*c05d8e5dSAndroid Build Coastguard Worker
408*c05d8e5dSAndroid Build Coastguard Worker /// ARM Constructor
InitByteFutexInitByteFutex409*c05d8e5dSAndroid Build Coastguard Worker explicit InitByteFutex(uint32_t *g) : BaseT(g),
410*c05d8e5dSAndroid Build Coastguard Worker init_byte(this->init_byte_address),
411*c05d8e5dSAndroid Build Coastguard Worker has_thread_id_support(this->thread_id_address && GetThreadIDArg),
412*c05d8e5dSAndroid Build Coastguard Worker thread_id(this->thread_id_address) {}
413*c05d8e5dSAndroid Build Coastguard Worker
414*c05d8e5dSAndroid Build Coastguard Worker /// Itanium Constructor
InitByteFutexInitByteFutex415*c05d8e5dSAndroid Build Coastguard Worker explicit InitByteFutex(uint64_t *g) : BaseT(g),
416*c05d8e5dSAndroid Build Coastguard Worker init_byte(this->init_byte_address),
417*c05d8e5dSAndroid Build Coastguard Worker has_thread_id_support(this->thread_id_address && GetThreadIDArg),
418*c05d8e5dSAndroid Build Coastguard Worker thread_id(this->thread_id_address) {}
419*c05d8e5dSAndroid Build Coastguard Worker
420*c05d8e5dSAndroid Build Coastguard Worker public:
acquire_init_byteInitByteFutex421*c05d8e5dSAndroid Build Coastguard Worker AcquireResult acquire_init_byte() {
422*c05d8e5dSAndroid Build Coastguard Worker while (true) {
423*c05d8e5dSAndroid Build Coastguard Worker uint8_t last_val = UNSET;
424*c05d8e5dSAndroid Build Coastguard Worker if (init_byte.compare_exchange(&last_val, PENDING_BIT, std::_AO_Acq_Rel,
425*c05d8e5dSAndroid Build Coastguard Worker std::_AO_Acquire)) {
426*c05d8e5dSAndroid Build Coastguard Worker if (has_thread_id_support) {
427*c05d8e5dSAndroid Build Coastguard Worker thread_id.store(current_thread_id.get(), std::_AO_Relaxed);
428*c05d8e5dSAndroid Build Coastguard Worker }
429*c05d8e5dSAndroid Build Coastguard Worker return INIT_IS_PENDING;
430*c05d8e5dSAndroid Build Coastguard Worker }
431*c05d8e5dSAndroid Build Coastguard Worker
432*c05d8e5dSAndroid Build Coastguard Worker if (last_val == COMPLETE_BIT)
433*c05d8e5dSAndroid Build Coastguard Worker return INIT_IS_DONE;
434*c05d8e5dSAndroid Build Coastguard Worker
435*c05d8e5dSAndroid Build Coastguard Worker if (last_val & PENDING_BIT) {
436*c05d8e5dSAndroid Build Coastguard Worker
437*c05d8e5dSAndroid Build Coastguard Worker // Check for recursive initialization
438*c05d8e5dSAndroid Build Coastguard Worker if (has_thread_id_support && thread_id.load(std::_AO_Relaxed) == current_thread_id.get()) {
439*c05d8e5dSAndroid Build Coastguard Worker ABORT_WITH_MESSAGE("__cxa_guard_acquire detected recursive initialization");
440*c05d8e5dSAndroid Build Coastguard Worker }
441*c05d8e5dSAndroid Build Coastguard Worker
442*c05d8e5dSAndroid Build Coastguard Worker if ((last_val & WAITING_BIT) == 0) {
443*c05d8e5dSAndroid Build Coastguard Worker // This compare exchange can fail for several reasons
444*c05d8e5dSAndroid Build Coastguard Worker // (1) another thread finished the whole thing before we got here
445*c05d8e5dSAndroid Build Coastguard Worker // (2) another thread set the waiting bit we were trying to thread
446*c05d8e5dSAndroid Build Coastguard Worker // (3) another thread had an exception and failed to finish
447*c05d8e5dSAndroid Build Coastguard Worker if (!init_byte.compare_exchange(&last_val, PENDING_BIT | WAITING_BIT,
448*c05d8e5dSAndroid Build Coastguard Worker std::_AO_Acq_Rel, std::_AO_Release)) {
449*c05d8e5dSAndroid Build Coastguard Worker // (1) success, via someone else's work!
450*c05d8e5dSAndroid Build Coastguard Worker if (last_val == COMPLETE_BIT)
451*c05d8e5dSAndroid Build Coastguard Worker return INIT_IS_DONE;
452*c05d8e5dSAndroid Build Coastguard Worker
453*c05d8e5dSAndroid Build Coastguard Worker // (3) someone else, bailed on doing the work, retry from the start!
454*c05d8e5dSAndroid Build Coastguard Worker if (last_val == UNSET)
455*c05d8e5dSAndroid Build Coastguard Worker continue;
456*c05d8e5dSAndroid Build Coastguard Worker
457*c05d8e5dSAndroid Build Coastguard Worker // (2) the waiting bit got set, so we are happy to keep waiting
458*c05d8e5dSAndroid Build Coastguard Worker }
459*c05d8e5dSAndroid Build Coastguard Worker }
460*c05d8e5dSAndroid Build Coastguard Worker wait_on_initialization();
461*c05d8e5dSAndroid Build Coastguard Worker }
462*c05d8e5dSAndroid Build Coastguard Worker }
463*c05d8e5dSAndroid Build Coastguard Worker }
464*c05d8e5dSAndroid Build Coastguard Worker
release_init_byteInitByteFutex465*c05d8e5dSAndroid Build Coastguard Worker void release_init_byte() {
466*c05d8e5dSAndroid Build Coastguard Worker uint8_t old = init_byte.exchange(COMPLETE_BIT, std::_AO_Acq_Rel);
467*c05d8e5dSAndroid Build Coastguard Worker if (old & WAITING_BIT)
468*c05d8e5dSAndroid Build Coastguard Worker wake_all();
469*c05d8e5dSAndroid Build Coastguard Worker }
470*c05d8e5dSAndroid Build Coastguard Worker
abort_init_byteInitByteFutex471*c05d8e5dSAndroid Build Coastguard Worker void abort_init_byte() {
472*c05d8e5dSAndroid Build Coastguard Worker if (has_thread_id_support)
473*c05d8e5dSAndroid Build Coastguard Worker thread_id.store(0, std::_AO_Relaxed);
474*c05d8e5dSAndroid Build Coastguard Worker
475*c05d8e5dSAndroid Build Coastguard Worker uint8_t old = init_byte.exchange(0, std::_AO_Acq_Rel);
476*c05d8e5dSAndroid Build Coastguard Worker if (old & WAITING_BIT)
477*c05d8e5dSAndroid Build Coastguard Worker wake_all();
478*c05d8e5dSAndroid Build Coastguard Worker }
479*c05d8e5dSAndroid Build Coastguard Worker
480*c05d8e5dSAndroid Build Coastguard Worker private:
481*c05d8e5dSAndroid Build Coastguard Worker /// Use the futex to wait on the current guard variable. Futex expects a
482*c05d8e5dSAndroid Build Coastguard Worker /// 32-bit 4-byte aligned address as the first argument, so we have to use use
483*c05d8e5dSAndroid Build Coastguard Worker /// the base address of the guard variable (not the init byte).
wait_on_initializationInitByteFutex484*c05d8e5dSAndroid Build Coastguard Worker void wait_on_initialization() {
485*c05d8e5dSAndroid Build Coastguard Worker Wait(static_cast<int*>(this->base_address),
486*c05d8e5dSAndroid Build Coastguard Worker expected_value_for_futex(PENDING_BIT | WAITING_BIT));
487*c05d8e5dSAndroid Build Coastguard Worker }
wake_allInitByteFutex488*c05d8e5dSAndroid Build Coastguard Worker void wake_all() { Wake(static_cast<int*>(this->base_address)); }
489*c05d8e5dSAndroid Build Coastguard Worker
490*c05d8e5dSAndroid Build Coastguard Worker private:
491*c05d8e5dSAndroid Build Coastguard Worker AtomicInt<uint8_t> init_byte;
492*c05d8e5dSAndroid Build Coastguard Worker
493*c05d8e5dSAndroid Build Coastguard Worker const bool has_thread_id_support;
494*c05d8e5dSAndroid Build Coastguard Worker // Unsafe to use unless has_thread_id_support
495*c05d8e5dSAndroid Build Coastguard Worker AtomicInt<uint32_t> thread_id;
496*c05d8e5dSAndroid Build Coastguard Worker LazyValue<uint32_t, GetThreadIDArg> current_thread_id;
497*c05d8e5dSAndroid Build Coastguard Worker
498*c05d8e5dSAndroid Build Coastguard Worker /// Create the expected integer value for futex `wait(int* addr, int expected)`.
499*c05d8e5dSAndroid Build Coastguard Worker /// We pass the base address as the first argument, So this function creates
500*c05d8e5dSAndroid Build Coastguard Worker /// an zero-initialized integer with `b` copied at the correct offset.
expected_value_for_futexInitByteFutex501*c05d8e5dSAndroid Build Coastguard Worker static int expected_value_for_futex(uint8_t b) {
502*c05d8e5dSAndroid Build Coastguard Worker int dest_val = 0;
503*c05d8e5dSAndroid Build Coastguard Worker std::memcpy(reinterpret_cast<char*>(&dest_val) + 1, &b, 1);
504*c05d8e5dSAndroid Build Coastguard Worker return dest_val;
505*c05d8e5dSAndroid Build Coastguard Worker }
506*c05d8e5dSAndroid Build Coastguard Worker
507*c05d8e5dSAndroid Build Coastguard Worker static_assert(Wait != nullptr && Wake != nullptr, "");
508*c05d8e5dSAndroid Build Coastguard Worker };
509*c05d8e5dSAndroid Build Coastguard Worker
510*c05d8e5dSAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
511*c05d8e5dSAndroid Build Coastguard Worker //
512*c05d8e5dSAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
513*c05d8e5dSAndroid Build Coastguard Worker
514*c05d8e5dSAndroid Build Coastguard Worker template <class T>
515*c05d8e5dSAndroid Build Coastguard Worker struct GlobalStatic {
516*c05d8e5dSAndroid Build Coastguard Worker static T instance;
517*c05d8e5dSAndroid Build Coastguard Worker };
518*c05d8e5dSAndroid Build Coastguard Worker template <class T>
519*c05d8e5dSAndroid Build Coastguard Worker _LIBCPP_SAFE_STATIC T GlobalStatic<T>::instance = {};
520*c05d8e5dSAndroid Build Coastguard Worker
521*c05d8e5dSAndroid Build Coastguard Worker enum class Implementation {
522*c05d8e5dSAndroid Build Coastguard Worker NoThreads,
523*c05d8e5dSAndroid Build Coastguard Worker GlobalLock,
524*c05d8e5dSAndroid Build Coastguard Worker Futex
525*c05d8e5dSAndroid Build Coastguard Worker };
526*c05d8e5dSAndroid Build Coastguard Worker
527*c05d8e5dSAndroid Build Coastguard Worker template <Implementation Impl>
528*c05d8e5dSAndroid Build Coastguard Worker struct SelectImplementation;
529*c05d8e5dSAndroid Build Coastguard Worker
530*c05d8e5dSAndroid Build Coastguard Worker template <>
531*c05d8e5dSAndroid Build Coastguard Worker struct SelectImplementation<Implementation::NoThreads> {
532*c05d8e5dSAndroid Build Coastguard Worker using type = InitByteNoThreads;
533*c05d8e5dSAndroid Build Coastguard Worker };
534*c05d8e5dSAndroid Build Coastguard Worker
535*c05d8e5dSAndroid Build Coastguard Worker template <>
536*c05d8e5dSAndroid Build Coastguard Worker struct SelectImplementation<Implementation::GlobalLock> {
537*c05d8e5dSAndroid Build Coastguard Worker using type = InitByteGlobalMutex<
538*c05d8e5dSAndroid Build Coastguard Worker LibcppMutex, LibcppCondVar, GlobalStatic<LibcppMutex>::instance,
539*c05d8e5dSAndroid Build Coastguard Worker GlobalStatic<LibcppCondVar>::instance, PlatformThreadID>;
540*c05d8e5dSAndroid Build Coastguard Worker };
541*c05d8e5dSAndroid Build Coastguard Worker
542*c05d8e5dSAndroid Build Coastguard Worker template <>
543*c05d8e5dSAndroid Build Coastguard Worker struct SelectImplementation<Implementation::Futex> {
544*c05d8e5dSAndroid Build Coastguard Worker using type =
545*c05d8e5dSAndroid Build Coastguard Worker InitByteFutex<PlatformFutexWait, PlatformFutexWake, PlatformThreadID>;
546*c05d8e5dSAndroid Build Coastguard Worker };
547*c05d8e5dSAndroid Build Coastguard Worker
548*c05d8e5dSAndroid Build Coastguard Worker // TODO(EricWF): We should prefer the futex implementation when available. But
549*c05d8e5dSAndroid Build Coastguard Worker // it should be done in a separate step from adding the implementation.
550*c05d8e5dSAndroid Build Coastguard Worker constexpr Implementation CurrentImplementation =
551*c05d8e5dSAndroid Build Coastguard Worker #if defined(_LIBCXXABI_HAS_NO_THREADS)
552*c05d8e5dSAndroid Build Coastguard Worker Implementation::NoThreads;
553*c05d8e5dSAndroid Build Coastguard Worker #elif defined(_LIBCXXABI_USE_FUTEX)
554*c05d8e5dSAndroid Build Coastguard Worker Implementation::Futex;
555*c05d8e5dSAndroid Build Coastguard Worker #else
556*c05d8e5dSAndroid Build Coastguard Worker Implementation::GlobalLock;
557*c05d8e5dSAndroid Build Coastguard Worker #endif
558*c05d8e5dSAndroid Build Coastguard Worker
559*c05d8e5dSAndroid Build Coastguard Worker static_assert(CurrentImplementation != Implementation::Futex
560*c05d8e5dSAndroid Build Coastguard Worker || PlatformSupportsFutex(), "Futex selected but not supported");
561*c05d8e5dSAndroid Build Coastguard Worker
562*c05d8e5dSAndroid Build Coastguard Worker using SelectedImplementation =
563*c05d8e5dSAndroid Build Coastguard Worker SelectImplementation<CurrentImplementation>::type;
564*c05d8e5dSAndroid Build Coastguard Worker
565*c05d8e5dSAndroid Build Coastguard Worker } // end namespace
566*c05d8e5dSAndroid Build Coastguard Worker } // end namespace __cxxabiv1
567*c05d8e5dSAndroid Build Coastguard Worker
568*c05d8e5dSAndroid Build Coastguard Worker #endif // LIBCXXABI_SRC_INCLUDE_CXA_GUARD_IMPL_H
569