| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #define TESTING_CXA_GUARD |
| | #include "../src/cxa_guard_impl.h" |
| | #include <cassert> |
| |
|
| | 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: |
| | |
| | |
| | |
| | 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() { |
| | { |
| | #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__)) && !defined(_LIBCXXABI_HAS_NO_THREADS) |
| | assert(PlatformThreadID); |
| | #endif |
| | if (PlatformSupportsThreadID()) { |
| | 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(); |
| | } |
| | } |
| |
|