xref: /llvm-project/libcxxabi/test/guard_test_basic.pass.cpp (revision 947dfc95ca914385c181f24bbc1a16143c17b5f0)
170ebeabfSEric Fiselier //===----------------------------------------------------------------------===//
270ebeabfSEric Fiselier //
370ebeabfSEric Fiselier // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
470ebeabfSEric Fiselier // See https://llvm.org/LICENSE.txt for license information.
570ebeabfSEric Fiselier // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
670ebeabfSEric Fiselier //
770ebeabfSEric Fiselier //===----------------------------------------------------------------------===//
870ebeabfSEric Fiselier //
931cbe0f2SLouis Dionne // UNSUPPORTED: c++03
1070ebeabfSEric Fiselier 
11851bfc07SLouis Dionne // Necessary because we include a private header of libc++abi, which
12851bfc07SLouis Dionne // only understands _LIBCXXABI_HAS_NO_THREADS.
13851bfc07SLouis Dionne #include "test_macros.h"
14851bfc07SLouis Dionne #ifdef TEST_HAS_NO_THREADS
15851bfc07SLouis Dionne # define _LIBCXXABI_HAS_NO_THREADS
16851bfc07SLouis Dionne #endif
17851bfc07SLouis Dionne 
1870ebeabfSEric Fiselier #define TESTING_CXA_GUARD
1970ebeabfSEric Fiselier #include "../src/cxa_guard_impl.h"
207568899bSDavid Zarzycki #include <cassert>
21*947dfc95SNikolas Klauser #include <type_traits>
2270ebeabfSEric Fiselier 
233601ee6cSDaniel McIntosh #if defined(__clang__)
243601ee6cSDaniel McIntosh #  pragma clang diagnostic ignored "-Wtautological-pointer-compare"
253601ee6cSDaniel McIntosh #elif defined(__GNUC__)
268d313927SLouis Dionne #  pragma GCC diagnostic ignored "-Waddress"
278d313927SLouis Dionne #endif
288d313927SLouis Dionne 
2970ebeabfSEric Fiselier using namespace __cxxabiv1;
3070ebeabfSEric Fiselier 
3170ebeabfSEric Fiselier template <class GuardType, class Impl>
3270ebeabfSEric Fiselier struct Tests {
3370ebeabfSEric Fiselier private:
TestsTests3470ebeabfSEric Fiselier   Tests() : g{}, impl(&g) {}
3570ebeabfSEric Fiselier   GuardType g;
3670ebeabfSEric Fiselier   Impl impl;
3770ebeabfSEric Fiselier 
first_byteTests3870ebeabfSEric Fiselier   uint8_t first_byte() {
3970ebeabfSEric Fiselier     uint8_t first;
4070ebeabfSEric Fiselier     std::memcpy(&first, &g, 1);
4170ebeabfSEric Fiselier     return first;
4270ebeabfSEric Fiselier   }
4370ebeabfSEric Fiselier 
resetTests4470ebeabfSEric Fiselier   void reset() { g = {}; }
4570ebeabfSEric Fiselier 
4670ebeabfSEric Fiselier public:
4770ebeabfSEric Fiselier   // Test the post conditions on cxa_guard_acquire, cxa_guard_abort, and
4870ebeabfSEric Fiselier   // cxa_guard_release. Specifically, that they leave the first byte with
4970ebeabfSEric Fiselier   // the value 0 or 1 as specified by the ARM or Itanium specification.
testTests5070ebeabfSEric Fiselier   static void test() {
5170ebeabfSEric Fiselier     Tests tests;
5270ebeabfSEric Fiselier     tests.test_acquire();
5370ebeabfSEric Fiselier     tests.test_abort();
5470ebeabfSEric Fiselier     tests.test_release();
5570ebeabfSEric Fiselier   }
5670ebeabfSEric Fiselier 
test_acquireTests5770ebeabfSEric Fiselier   void test_acquire() {
5870ebeabfSEric Fiselier     {
5970ebeabfSEric Fiselier       reset();
6070ebeabfSEric Fiselier       assert(first_byte() == 0);
6170ebeabfSEric Fiselier       assert(impl.cxa_guard_acquire() == INIT_IS_PENDING);
6270ebeabfSEric Fiselier       assert(first_byte() == 0);
6370ebeabfSEric Fiselier     }
6470ebeabfSEric Fiselier     {
6570ebeabfSEric Fiselier       reset();
6670ebeabfSEric Fiselier       assert(first_byte() == 0);
6770ebeabfSEric Fiselier       assert(impl.cxa_guard_acquire() == INIT_IS_PENDING);
6870ebeabfSEric Fiselier       impl.cxa_guard_release();
6970ebeabfSEric Fiselier       assert(first_byte() == 1);
7070ebeabfSEric Fiselier       assert(impl.cxa_guard_acquire() == INIT_IS_DONE);
7170ebeabfSEric Fiselier     }
7270ebeabfSEric Fiselier   }
7370ebeabfSEric Fiselier 
test_releaseTests7470ebeabfSEric Fiselier   void test_release() {
7570ebeabfSEric Fiselier     {
7670ebeabfSEric Fiselier       reset();
7770ebeabfSEric Fiselier       assert(first_byte() == 0);
7870ebeabfSEric Fiselier       assert(impl.cxa_guard_acquire() == INIT_IS_PENDING);
7970ebeabfSEric Fiselier       assert(first_byte() == 0);
8070ebeabfSEric Fiselier       impl.cxa_guard_release();
8170ebeabfSEric Fiselier       assert(first_byte() == 1);
8270ebeabfSEric Fiselier     }
8370ebeabfSEric Fiselier   }
8470ebeabfSEric Fiselier 
test_abortTests8570ebeabfSEric Fiselier   void test_abort() {
8670ebeabfSEric Fiselier     {
8770ebeabfSEric Fiselier       reset();
8870ebeabfSEric Fiselier       assert(first_byte() == 0);
8970ebeabfSEric Fiselier       assert(impl.cxa_guard_acquire() == INIT_IS_PENDING);
9070ebeabfSEric Fiselier       assert(first_byte() == 0);
9170ebeabfSEric Fiselier       impl.cxa_guard_abort();
9270ebeabfSEric Fiselier       assert(first_byte() == 0);
9370ebeabfSEric Fiselier       assert(impl.cxa_guard_acquire() == INIT_IS_PENDING);
9470ebeabfSEric Fiselier       assert(first_byte() == 0);
9570ebeabfSEric Fiselier     }
9670ebeabfSEric Fiselier   }
9770ebeabfSEric Fiselier };
9870ebeabfSEric Fiselier 
9970ebeabfSEric Fiselier struct NopMutex {
lockNopMutex10070ebeabfSEric Fiselier   bool lock() {
10170ebeabfSEric Fiselier     assert(!is_locked);
10270ebeabfSEric Fiselier     is_locked = true;
10370ebeabfSEric Fiselier     return false;
10470ebeabfSEric Fiselier   }
unlockNopMutex10570ebeabfSEric Fiselier   bool unlock() {
10670ebeabfSEric Fiselier     assert(is_locked);
10770ebeabfSEric Fiselier     is_locked = false;
10870ebeabfSEric Fiselier     return false;
10970ebeabfSEric Fiselier   }
11070ebeabfSEric Fiselier 
11170ebeabfSEric Fiselier private:
11270ebeabfSEric Fiselier   bool is_locked = false;
11370ebeabfSEric Fiselier };
11427fd2f60SEric Fiselier NopMutex global_nop_mutex = {};
11570ebeabfSEric Fiselier 
11670ebeabfSEric Fiselier struct NopCondVar {
broadcastNopCondVar11770ebeabfSEric Fiselier   bool broadcast() { return false; }
waitNopCondVar11870ebeabfSEric Fiselier   bool wait(NopMutex&) { return false; }
11970ebeabfSEric Fiselier };
12027fd2f60SEric Fiselier NopCondVar global_nop_cond = {};
12170ebeabfSEric Fiselier 
NopFutexWait(int *,int)12270ebeabfSEric Fiselier void NopFutexWait(int*, int) { assert(false); }
NopFutexWake(int *)12370ebeabfSEric Fiselier void NopFutexWake(int*) { assert(false); }
MockGetThreadID()12470ebeabfSEric Fiselier uint32_t MockGetThreadID() { return 0; }
12570ebeabfSEric Fiselier 
main(int,char **)126504bc07dSLouis Dionne int main(int, char**) {
12770ebeabfSEric Fiselier   {
128851bfc07SLouis Dionne #if defined(TEST_HAS_NO_THREADS)
12970ebeabfSEric Fiselier     static_assert(CurrentImplementation == Implementation::NoThreads, "");
130f011a53cSDaniel McIntosh     static_assert(std::is_same<SelectedImplementation, NoThreadsGuard>::value, "");
13170ebeabfSEric Fiselier #else
132e42eeb88SDaniel McIntosh     static_assert(CurrentImplementation == Implementation::GlobalMutex, "");
133f011a53cSDaniel McIntosh     static_assert(std::is_same<SelectedImplementation,
134f011a53cSDaniel McIntosh                                GlobalMutexGuard<LibcppMutex, LibcppCondVar, GlobalStatic<LibcppMutex>::instance,
135f011a53cSDaniel McIntosh                                                 GlobalStatic<LibcppCondVar>::instance>>::value,
13670ebeabfSEric Fiselier                   "");
13770ebeabfSEric Fiselier #endif
13870ebeabfSEric Fiselier   }
13970ebeabfSEric Fiselier   {
140851bfc07SLouis Dionne #if (defined(__APPLE__) || defined(__linux__))  && !defined(TEST_HAS_NO_THREADS)
14170ebeabfSEric Fiselier     assert(PlatformThreadID);
14270ebeabfSEric Fiselier #endif
1433601ee6cSDaniel McIntosh     if (PlatformThreadID != nullptr) {
14470ebeabfSEric Fiselier       assert(PlatformThreadID() != 0);
14570ebeabfSEric Fiselier       assert(PlatformThreadID() == PlatformThreadID());
14670ebeabfSEric Fiselier     }
14770ebeabfSEric Fiselier   }
14870ebeabfSEric Fiselier   {
149f011a53cSDaniel McIntosh     Tests<uint32_t, NoThreadsGuard>::test();
150f011a53cSDaniel McIntosh     Tests<uint64_t, NoThreadsGuard>::test();
15170ebeabfSEric Fiselier   }
15270ebeabfSEric Fiselier   {
153f011a53cSDaniel McIntosh     using MutexImpl = GlobalMutexGuard<NopMutex, NopCondVar, global_nop_mutex, global_nop_cond, MockGetThreadID>;
15470ebeabfSEric Fiselier     Tests<uint32_t, MutexImpl>::test();
15570ebeabfSEric Fiselier     Tests<uint64_t, MutexImpl>::test();
15670ebeabfSEric Fiselier   }
15770ebeabfSEric Fiselier   {
158f011a53cSDaniel McIntosh     using FutexImpl = FutexGuard<&NopFutexWait, &NopFutexWake, &MockGetThreadID>;
15970ebeabfSEric Fiselier     Tests<uint32_t, FutexImpl>::test();
16070ebeabfSEric Fiselier     Tests<uint64_t, FutexImpl>::test();
16170ebeabfSEric Fiselier   }
162504bc07dSLouis Dionne 
163504bc07dSLouis Dionne   return 0;
16470ebeabfSEric Fiselier }
165