llvm-project
164 строки · 4.3 Кб
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:
34Tests() : g{}, impl(&g) {}
35GuardType g;
36Impl impl;
37
38uint8_t first_byte() {
39uint8_t first;
40std::memcpy(&first, &g, 1);
41return first;
42}
43
44void 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.
50static void test() {
51Tests tests;
52tests.test_acquire();
53tests.test_abort();
54tests.test_release();
55}
56
57void test_acquire() {
58{
59reset();
60assert(first_byte() == 0);
61assert(impl.cxa_guard_acquire() == INIT_IS_PENDING);
62assert(first_byte() == 0);
63}
64{
65reset();
66assert(first_byte() == 0);
67assert(impl.cxa_guard_acquire() == INIT_IS_PENDING);
68impl.cxa_guard_release();
69assert(first_byte() == 1);
70assert(impl.cxa_guard_acquire() == INIT_IS_DONE);
71}
72}
73
74void test_release() {
75{
76reset();
77assert(first_byte() == 0);
78assert(impl.cxa_guard_acquire() == INIT_IS_PENDING);
79assert(first_byte() == 0);
80impl.cxa_guard_release();
81assert(first_byte() == 1);
82}
83}
84
85void test_abort() {
86{
87reset();
88assert(first_byte() == 0);
89assert(impl.cxa_guard_acquire() == INIT_IS_PENDING);
90assert(first_byte() == 0);
91impl.cxa_guard_abort();
92assert(first_byte() == 0);
93assert(impl.cxa_guard_acquire() == INIT_IS_PENDING);
94assert(first_byte() == 0);
95}
96}
97};
98
99struct NopMutex {
100bool lock() {
101assert(!is_locked);
102is_locked = true;
103return false;
104}
105bool unlock() {
106assert(is_locked);
107is_locked = false;
108return false;
109}
110
111private:
112bool is_locked = false;
113};
114NopMutex global_nop_mutex = {};
115
116struct NopCondVar {
117bool broadcast() { return false; }
118bool 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)
129static_assert(CurrentImplementation == Implementation::NoThreads, "");
130static_assert(std::is_same<SelectedImplementation, NoThreadsGuard>::value, "");
131#else
132static_assert(CurrentImplementation == Implementation::GlobalMutex, "");
133static_assert(std::is_same<SelectedImplementation,
134GlobalMutexGuard<LibcppMutex, LibcppCondVar, GlobalStatic<LibcppMutex>::instance,
135GlobalStatic<LibcppCondVar>::instance>>::value,
136"");
137#endif
138}
139{
140#if (defined(__APPLE__) || defined(__linux__)) && !defined(TEST_HAS_NO_THREADS)
141assert(PlatformThreadID);
142#endif
143if (PlatformThreadID != nullptr) {
144assert(PlatformThreadID() != 0);
145assert(PlatformThreadID() == PlatformThreadID());
146}
147}
148{
149Tests<uint32_t, NoThreadsGuard>::test();
150Tests<uint64_t, NoThreadsGuard>::test();
151}
152{
153using MutexImpl = GlobalMutexGuard<NopMutex, NopCondVar, global_nop_mutex, global_nop_cond, MockGetThreadID>;
154Tests<uint32_t, MutexImpl>::test();
155Tests<uint64_t, MutexImpl>::test();
156}
157{
158using FutexImpl = FutexGuard<&NopFutexWait, &NopFutexWake, &MockGetThreadID>;
159Tests<uint32_t, FutexImpl>::test();
160Tests<uint64_t, FutexImpl>::test();
161}
162
163return 0;
164}
165