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++03
10
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
16#endif
17
18#define TESTING_CXA_GUARD
19#include "../src/cxa_guard_impl.h"
20#include <cassert>
21#include <type_traits>
22
23#if defined(__clang__)
24# pragma clang diagnostic ignored "-Wtautological-pointer-compare"
25#elif defined(__GNUC__)
26# pragma GCC diagnostic ignored "-Waddress"
27#endif
28
29using namespace __cxxabiv1;
30
31template <class GuardType, class Impl>
32struct Tests {
33private:
34 Tests() : g{}, impl(&g) {}
35 GuardType g;
36 Impl impl;
37
38 uint8_t first_byte() {
39 uint8_t first;
40 std::memcpy(dest: &first, src: &g, n: 1);
41 return first;
42 }
43
44 void reset() { g = {}; }
45
46public:
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.
50 static void test() {
51 Tests tests;
52 tests.test_acquire();
53 tests.test_abort();
54 tests.test_release();
55 }
56
57 void test_acquire() {
58 {
59 reset();
60 assert(first_byte() == 0);
61 assert(impl.cxa_guard_acquire() == INIT_IS_PENDING);
62 assert(first_byte() == 0);
63 }
64 {
65 reset();
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);
71 }
72 }
73
74 void test_release() {
75 {
76 reset();
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);
82 }
83 }
84
85 void test_abort() {
86 {
87 reset();
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);
95 }
96 }
97};
98
99struct NopMutex {
100 bool lock() {
101 assert(!is_locked);
102 is_locked = true;
103 return false;
104 }
105 bool unlock() {
106 assert(is_locked);
107 is_locked = false;
108 return false;
109 }
110
111private:
112 bool is_locked = false;
113};
114NopMutex global_nop_mutex = {};
115
116struct NopCondVar {
117 bool broadcast() { return false; }
118 bool wait(NopMutex&) { return false; }
119};
120NopCondVar global_nop_cond = {};
121
122void NopFutexWait(int*, int) { assert(false); }
123void NopFutexWake(int*) { assert(false); }
124uint32_t MockGetThreadID() { return 0; }
125
126int main(int, char**) {
127 {
128#if defined(TEST_HAS_NO_THREADS)
129 static_assert(CurrentImplementation == Implementation::NoThreads, "");
130 static_assert(std::is_same<SelectedImplementation, NoThreadsGuard>::value, "");
131#else
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,
136 "");
137#endif
138 }
139 {
140#if (defined(__APPLE__) || defined(__linux__)) && !defined(TEST_HAS_NO_THREADS)
141 assert(PlatformThreadID);
142#endif
143 if (PlatformThreadID != nullptr) {
144 assert(PlatformThreadID() != 0);
145 assert(PlatformThreadID() == PlatformThreadID());
146 }
147 }
148 {
149 Tests<uint32_t, NoThreadsGuard>::test();
150 Tests<uint64_t, NoThreadsGuard>::test();
151 }
152 {
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();
156 }
157 {
158 using FutexImpl = FutexGuard<&NopFutexWait, &NopFutexWake, &MockGetThreadID>;
159 Tests<uint32_t, FutexImpl>::test();
160 Tests<uint64_t, FutexImpl>::test();
161 }
162
163 return 0;
164}
165

source code of libcxxabi/test/guard_test_basic.pass.cpp