165 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// UNSUPPORTED: c++0310 11// Necessary because we include a private header of libc++abi, which12// only understands _LIBCXXABI_HAS_NO_THREADS.13#include "test_macros.h"14#ifdef TEST_HAS_NO_THREADS15# define _LIBCXXABI_HAS_NO_THREADS16#endif17 18#define TESTING_CXA_GUARD19#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#endif28 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(&first, &g, 1);41 return first;42 }43 44 void reset() { g = {}; }45 46public:47 // Test the post conditions on cxa_guard_acquire, cxa_guard_abort, and48 // cxa_guard_release. Specifically, that they leave the first byte with49 // 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#else132 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#endif138 }139 {140#if (defined(__APPLE__) || defined(__linux__)) && !defined(TEST_HAS_NO_THREADS)141 assert(PlatformThreadID);142#endif143 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