blob: a325dd0b732a472377a75cfc7f1013ac055166bf [file] [log] [blame]
Eric Fiselier70ebeab2019-04-24 01:47:301//===----------------------------------------------------------------------===//
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
14using namespace __cxxabiv1;
15
16template <class GuardType, class Impl>
17struct Tests {
18private:
19 Tests() : g{}, impl(&g) {}
20 GuardType g;
21 Impl impl;
22
23 uint8_t first_byte() {
24 uint8_t first;
25 std::memcpy(&first, &g, 1);
26 return first;
27 }
28
29 void reset() { g = {}; }
30
31public:
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.
35 static void test() {
36 Tests tests;
37 tests.test_acquire();
38 tests.test_abort();
39 tests.test_release();
40 }
41
42 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
59 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
70 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
84struct NopMutex {
85 bool lock() {
86 assert(!is_locked);
87 is_locked = true;
88 return false;
89 }
90 bool unlock() {
91 assert(is_locked);
92 is_locked = false;
93 return false;
94 }
95
96private:
97 bool is_locked = false;
98};
Eric Fiselier27fd2f62019-04-24 02:21:1399NopMutex global_nop_mutex = {};
Eric Fiselier70ebeab2019-04-24 01:47:30100
101struct NopCondVar {
102 bool broadcast() { return false; }
103 bool wait(NopMutex&) { return false; }
104};
Eric Fiselier27fd2f62019-04-24 02:21:13105NopCondVar global_nop_cond = {};
Eric Fiselier70ebeab2019-04-24 01:47:30106
107void NopFutexWait(int*, int) { assert(false); }
108void NopFutexWake(int*) { assert(false); }
109uint32_t MockGetThreadID() { return 0; }
110
111int 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
Eric Fiselier5a235862019-04-24 04:21:05132 if (PlatformSupportsThreadID()) {
Eric Fiselier70ebeab2019-04-24 01:47:30133 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}