1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
|
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// UNSUPPORTED: c++03
// Necessary because we include a private header of libc++abi, which
// only understands _LIBCXXABI_HAS_NO_THREADS.
#include "test_macros.h"
#ifdef TEST_HAS_NO_THREADS
# define _LIBCXXABI_HAS_NO_THREADS
#endif
#define TESTING_CXA_GUARD
#include "../src/cxa_guard_impl.h"
#include <cassert>
#if defined(__clang__)
# pragma clang diagnostic ignored "-Wtautological-pointer-compare"
#elif defined(__GNUC__)
# pragma GCC diagnostic ignored "-Waddress"
#endif
using namespace __cxxabiv1;
template <class GuardType, class Impl>
struct Tests {
private:
Tests() : g{}, impl(&g) {}
GuardType g;
Impl impl;
uint8_t first_byte() {
uint8_t first;
std::memcpy(&first, &g, 1);
return first;
}
void reset() { g = {}; }
public:
// Test the post conditions on cxa_guard_acquire, cxa_guard_abort, and
// cxa_guard_release. Specifically, that they leave the first byte with
// the value 0 or 1 as specified by the ARM or Itanium specification.
static void test() {
Tests tests;
tests.test_acquire();
tests.test_abort();
tests.test_release();
}
void test_acquire() {
{
reset();
assert(first_byte() == 0);
assert(impl.cxa_guard_acquire() == INIT_IS_PENDING);
assert(first_byte() == 0);
}
{
reset();
assert(first_byte() == 0);
assert(impl.cxa_guard_acquire() == INIT_IS_PENDING);
impl.cxa_guard_release();
assert(first_byte() == 1);
assert(impl.cxa_guard_acquire() == INIT_IS_DONE);
}
}
void test_release() {
{
reset();
assert(first_byte() == 0);
assert(impl.cxa_guard_acquire() == INIT_IS_PENDING);
assert(first_byte() == 0);
impl.cxa_guard_release();
assert(first_byte() == 1);
}
}
void test_abort() {
{
reset();
assert(first_byte() == 0);
assert(impl.cxa_guard_acquire() == INIT_IS_PENDING);
assert(first_byte() == 0);
impl.cxa_guard_abort();
assert(first_byte() == 0);
assert(impl.cxa_guard_acquire() == INIT_IS_PENDING);
assert(first_byte() == 0);
}
}
};
struct NopMutex {
bool lock() {
assert(!is_locked);
is_locked = true;
return false;
}
bool unlock() {
assert(is_locked);
is_locked = false;
return false;
}
private:
bool is_locked = false;
};
NopMutex global_nop_mutex = {};
struct NopCondVar {
bool broadcast() { return false; }
bool wait(NopMutex&) { return false; }
};
NopCondVar global_nop_cond = {};
void NopFutexWait(int*, int) { assert(false); }
void NopFutexWake(int*) { assert(false); }
uint32_t MockGetThreadID() { return 0; }
int main(int, char**) {
{
#if defined(TEST_HAS_NO_THREADS)
static_assert(CurrentImplementation == Implementation::NoThreads, "");
static_assert(std::is_same<SelectedImplementation, NoThreadsGuard>::value, "");
#else
static_assert(CurrentImplementation == Implementation::GlobalMutex, "");
static_assert(std::is_same<SelectedImplementation,
GlobalMutexGuard<LibcppMutex, LibcppCondVar, GlobalStatic<LibcppMutex>::instance,
GlobalStatic<LibcppCondVar>::instance>>::value,
"");
#endif
}
{
#if (defined(__APPLE__) || defined(__linux__)) && !defined(TEST_HAS_NO_THREADS)
assert(PlatformThreadID);
#endif
if (PlatformThreadID != nullptr) {
assert(PlatformThreadID() != 0);
assert(PlatformThreadID() == PlatformThreadID());
}
}
{
Tests<uint32_t, NoThreadsGuard>::test();
Tests<uint64_t, NoThreadsGuard>::test();
}
{
using MutexImpl = GlobalMutexGuard<NopMutex, NopCondVar, global_nop_mutex, global_nop_cond, MockGetThreadID>;
Tests<uint32_t, MutexImpl>::test();
Tests<uint64_t, MutexImpl>::test();
}
{
using FutexImpl = FutexGuard<&NopFutexWait, &NopFutexWake, &MockGetThreadID>;
Tests<uint32_t, FutexImpl>::test();
Tests<uint64_t, FutexImpl>::test();
}
return 0;
}
|