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 // UNSUPPORTED: c++98, c++03
10
11 #define TESTING_CXA_GUARD
12 #include "../src/cxa_guard_impl.h"
13
14 using namespace __cxxabiv1;
15
16 template <class GuardType, class Impl>
17 struct Tests {
18 private:
TestsTests19 Tests() : g{}, impl(&g) {}
20 GuardType g;
21 Impl impl;
22
first_byteTests23 uint8_t first_byte() {
24 uint8_t first;
25 std::memcpy(&first, &g, 1);
26 return first;
27 }
28
resetTests29 void reset() { g = {}; }
30
31 public:
32 // Test the post conditions on cxa_guard_acquire, cxa_guard_abort, and
33 // cxa_guard_release. Specifically, that they leave the first byte with
34 // the value 0 or 1 as specified by the ARM or Itanium specification.
testTests35 static void test() {
36 Tests tests;
37 tests.test_acquire();
38 tests.test_abort();
39 tests.test_release();
40 }
41
test_acquireTests42 void test_acquire() {
43 {
44 reset();
45 assert(first_byte() == 0);
46 assert(impl.cxa_guard_acquire() == INIT_IS_PENDING);
47 assert(first_byte() == 0);
48 }
49 {
50 reset();
51 assert(first_byte() == 0);
52 assert(impl.cxa_guard_acquire() == INIT_IS_PENDING);
53 impl.cxa_guard_release();
54 assert(first_byte() == 1);
55 assert(impl.cxa_guard_acquire() == INIT_IS_DONE);
56 }
57 }
58
test_releaseTests59 void test_release() {
60 {
61 reset();
62 assert(first_byte() == 0);
63 assert(impl.cxa_guard_acquire() == INIT_IS_PENDING);
64 assert(first_byte() == 0);
65 impl.cxa_guard_release();
66 assert(first_byte() == 1);
67 }
68 }
69
test_abortTests70 void test_abort() {
71 {
72 reset();
73 assert(first_byte() == 0);
74 assert(impl.cxa_guard_acquire() == INIT_IS_PENDING);
75 assert(first_byte() == 0);
76 impl.cxa_guard_abort();
77 assert(first_byte() == 0);
78 assert(impl.cxa_guard_acquire() == INIT_IS_PENDING);
79 assert(first_byte() == 0);
80 }
81 }
82 };
83
84 struct NopMutex {
lockNopMutex85 bool lock() {
86 assert(!is_locked);
87 is_locked = true;
88 return false;
89 }
unlockNopMutex90 bool unlock() {
91 assert(is_locked);
92 is_locked = false;
93 return false;
94 }
95
96 private:
97 bool is_locked = false;
98 };
99 static NopMutex global_nop_mutex = {};
100
101 struct NopCondVar {
broadcastNopCondVar102 bool broadcast() { return false; }
waitNopCondVar103 bool wait(NopMutex&) { return false; }
104 };
105 static NopCondVar global_nop_cond = {};
106
NopFutexWait(int *,int)107 void NopFutexWait(int*, int) { assert(false); }
NopFutexWake(int *)108 void NopFutexWake(int*) { assert(false); }
MockGetThreadID()109 uint32_t MockGetThreadID() { return 0; }
110
main()111 int main() {
112 {
113 #if defined(_LIBCXXABI_HAS_NO_THREADS)
114 static_assert(CurrentImplementation == Implementation::NoThreads, "");
115 static_assert(
116 std::is_same<SelectedImplementation, InitByteNoThreads>::value, "");
117 #else
118 static_assert(CurrentImplementation == Implementation::GlobalLock, "");
119 static_assert(
120 std::is_same<
121 SelectedImplementation,
122 InitByteGlobalMutex<LibcppMutex, LibcppCondVar,
123 GlobalStatic<LibcppMutex>::instance,
124 GlobalStatic<LibcppCondVar>::instance>>::value,
125 "");
126 #endif
127 }
128 {
129 #if defined(__APPLE__) || defined(__linux__)
130 assert(PlatformThreadID);
131 #endif
132 if (PlatformSupportsThreadID()) {
133 assert(PlatformThreadID() != 0);
134 assert(PlatformThreadID() == PlatformThreadID());
135 }
136 }
137 {
138 Tests<uint32_t, InitByteNoThreads>::test();
139 Tests<uint64_t, InitByteNoThreads>::test();
140 }
141 {
142 using MutexImpl =
143 InitByteGlobalMutex<NopMutex, NopCondVar, global_nop_mutex,
144 global_nop_cond, MockGetThreadID>;
145 Tests<uint32_t, MutexImpl>::test();
146 Tests<uint64_t, MutexImpl>::test();
147 }
148 {
149 using FutexImpl =
150 InitByteFutex<&NopFutexWait, &NopFutexWake, &MockGetThreadID>;
151 Tests<uint32_t, FutexImpl>::test();
152 Tests<uint64_t, FutexImpl>::test();
153 }
154 }
155