diff options
Diffstat (limited to 'test/guard_test_basic.pass.cpp')
-rw-r--r-- | test/guard_test_basic.pass.cpp | 154 |
1 files changed, 154 insertions, 0 deletions
diff --git a/test/guard_test_basic.pass.cpp b/test/guard_test_basic.pass.cpp new file mode 100644 index 0000000..5f1576d --- /dev/null +++ b/test/guard_test_basic.pass.cpp @@ -0,0 +1,154 @@ +//===----------------------------------------------------------------------===// +// +// 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++98, c++03 + +#define TESTING_CXA_GUARD +#include "../src/cxa_guard_impl.h" + +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; +}; +static NopMutex global_nop_mutex = {}; + +struct NopCondVar { + bool broadcast() { return false; } + bool wait(NopMutex&) { return false; } +}; +static NopCondVar global_nop_cond = {}; + +void NopFutexWait(int*, int) { assert(false); } +void NopFutexWake(int*) { assert(false); } +uint32_t MockGetThreadID() { return 0; } + +int main() { + { +#if defined(_LIBCXXABI_HAS_NO_THREADS) + static_assert(CurrentImplementation == Implementation::NoThreads, ""); + static_assert( + std::is_same<SelectedImplementation, InitByteNoThreads>::value, ""); +#else + static_assert(CurrentImplementation == Implementation::GlobalLock, ""); + static_assert( + std::is_same< + SelectedImplementation, + InitByteGlobalMutex<LibcppMutex, LibcppCondVar, + GlobalStatic<LibcppMutex>::instance, + GlobalStatic<LibcppCondVar>::instance>>::value, + ""); +#endif + } + { +#if defined(__APPLE__) || defined(__linux__) + assert(PlatformThreadID); +#endif + if (+PlatformThreadID) { + assert(PlatformThreadID() != 0); + assert(PlatformThreadID() == PlatformThreadID()); + } + } + { + Tests<uint32_t, InitByteNoThreads>::test(); + Tests<uint64_t, InitByteNoThreads>::test(); + } + { + using MutexImpl = + InitByteGlobalMutex<NopMutex, NopCondVar, global_nop_mutex, + global_nop_cond, MockGetThreadID>; + Tests<uint32_t, MutexImpl>::test(); + Tests<uint64_t, MutexImpl>::test(); + } + { + using FutexImpl = + InitByteFutex<&NopFutexWait, &NopFutexWake, &MockGetThreadID>; + Tests<uint32_t, FutexImpl>::test(); + Tests<uint64_t, FutexImpl>::test(); + } +} |