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 //===----------------------------------------------------------------------===//
11 // Necessary because we include a private header of libc++abi, which
12 // only understands _LIBCXXABI_HAS_NO_THREADS.
13 #include "test_macros.h"
14 #ifdef TEST_HAS_NO_THREADS
15 # define _LIBCXXABI_HAS_NO_THREADS
18 #define TESTING_CXA_GUARD
19 #include "../src/cxa_guard_impl.h"
21 #include <type_traits>
23 #if defined(__clang__)
24 # pragma clang diagnostic ignored "-Wtautological-pointer-compare"
25 #elif defined(__GNUC__)
26 # pragma GCC diagnostic ignored "-Waddress"
29 using namespace __cxxabiv1
;
31 template <class GuardType
, class Impl
>
34 Tests() : g
{}, impl(&g
) {}
38 uint8_t first_byte() {
40 std::memcpy(&first
, &g
, 1);
44 void reset() { g
= {}; }
47 // Test the post conditions on cxa_guard_acquire, cxa_guard_abort, and
48 // cxa_guard_release. Specifically, that they leave the first byte with
49 // the value 0 or 1 as specified by the ARM or Itanium specification.
60 assert(first_byte() == 0);
61 assert(impl
.cxa_guard_acquire() == INIT_IS_PENDING
);
62 assert(first_byte() == 0);
66 assert(first_byte() == 0);
67 assert(impl
.cxa_guard_acquire() == INIT_IS_PENDING
);
68 impl
.cxa_guard_release();
69 assert(first_byte() == 1);
70 assert(impl
.cxa_guard_acquire() == INIT_IS_DONE
);
77 assert(first_byte() == 0);
78 assert(impl
.cxa_guard_acquire() == INIT_IS_PENDING
);
79 assert(first_byte() == 0);
80 impl
.cxa_guard_release();
81 assert(first_byte() == 1);
88 assert(first_byte() == 0);
89 assert(impl
.cxa_guard_acquire() == INIT_IS_PENDING
);
90 assert(first_byte() == 0);
91 impl
.cxa_guard_abort();
92 assert(first_byte() == 0);
93 assert(impl
.cxa_guard_acquire() == INIT_IS_PENDING
);
94 assert(first_byte() == 0);
112 bool is_locked
= false;
114 NopMutex global_nop_mutex
= {};
117 bool broadcast() { return false; }
118 bool wait(NopMutex
&) { return false; }
120 NopCondVar global_nop_cond
= {};
122 void NopFutexWait(int*, int) { assert(false); }
123 void NopFutexWake(int*) { assert(false); }
124 uint32_t MockGetThreadID() { return 0; }
126 int main(int, char**) {
128 #if defined(TEST_HAS_NO_THREADS)
129 static_assert(CurrentImplementation
== Implementation::NoThreads
, "");
130 static_assert(std::is_same
<SelectedImplementation
, NoThreadsGuard
>::value
, "");
132 static_assert(CurrentImplementation
== Implementation::GlobalMutex
, "");
133 static_assert(std::is_same
<SelectedImplementation
,
134 GlobalMutexGuard
<LibcppMutex
, LibcppCondVar
, GlobalStatic
<LibcppMutex
>::instance
,
135 GlobalStatic
<LibcppCondVar
>::instance
>>::value
,
140 #if (defined(__APPLE__) || defined(__linux__)) && !defined(TEST_HAS_NO_THREADS)
141 assert(PlatformThreadID
);
143 if (PlatformThreadID
!= nullptr) {
144 assert(PlatformThreadID() != 0);
145 assert(PlatformThreadID() == PlatformThreadID());
149 Tests
<uint32_t, NoThreadsGuard
>::test();
150 Tests
<uint64_t, NoThreadsGuard
>::test();
153 using MutexImpl
= GlobalMutexGuard
<NopMutex
, NopCondVar
, global_nop_mutex
, global_nop_cond
, MockGetThreadID
>;
154 Tests
<uint32_t, MutexImpl
>::test();
155 Tests
<uint64_t, MutexImpl
>::test();
158 using FutexImpl
= FutexGuard
<&NopFutexWait
, &NopFutexWake
, &MockGetThreadID
>;
159 Tests
<uint32_t, FutexImpl
>::test();
160 Tests
<uint64_t, FutexImpl
>::test();