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