xref: /aosp_15_r20/external/libcxxabi/test/guard_test_basic.pass.cpp (revision c05d8e5dc3e10f6ce4317e8bc22cc4a25f55fa94)
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