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