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
11*851bfc07SLouis Dionne // Necessary because we include a private header of libc++abi, which
12*851bfc07SLouis Dionne // only understands _LIBCXXABI_HAS_NO_THREADS.
13*851bfc07SLouis Dionne #include "test_macros.h"
14*851bfc07SLouis Dionne #ifdef TEST_HAS_NO_THREADS
15*851bfc07SLouis Dionne # define _LIBCXXABI_HAS_NO_THREADS
16*851bfc07SLouis Dionne #endif
17*851bfc07SLouis Dionne
1870ebeabfSEric Fiselier #define TESTING_CXA_GUARD
1970ebeabfSEric Fiselier #include "../src/cxa_guard_impl.h"
207568899bSDavid Zarzycki #include <cassert>
2170ebeabfSEric Fiselier
223601ee6cSDaniel McIntosh #if defined(__clang__)
233601ee6cSDaniel McIntosh # pragma clang diagnostic ignored "-Wtautological-pointer-compare"
243601ee6cSDaniel McIntosh #elif defined(__GNUC__)
258d313927SLouis Dionne # pragma GCC diagnostic ignored "-Waddress"
268d313927SLouis Dionne #endif
278d313927SLouis Dionne
2870ebeabfSEric Fiselier using namespace __cxxabiv1;
2970ebeabfSEric Fiselier
3070ebeabfSEric Fiselier template <class GuardType, class Impl>
3170ebeabfSEric Fiselier struct Tests {
3270ebeabfSEric Fiselier private:
TestsTests3370ebeabfSEric Fiselier Tests() : g{}, impl(&g) {}
3470ebeabfSEric Fiselier GuardType g;
3570ebeabfSEric Fiselier Impl impl;
3670ebeabfSEric Fiselier
first_byteTests3770ebeabfSEric Fiselier uint8_t first_byte() {
3870ebeabfSEric Fiselier uint8_t first;
3970ebeabfSEric Fiselier std::memcpy(&first, &g, 1);
4070ebeabfSEric Fiselier return first;
4170ebeabfSEric Fiselier }
4270ebeabfSEric Fiselier
resetTests4370ebeabfSEric Fiselier void reset() { g = {}; }
4470ebeabfSEric Fiselier
4570ebeabfSEric Fiselier public:
4670ebeabfSEric Fiselier // Test the post conditions on cxa_guard_acquire, cxa_guard_abort, and
4770ebeabfSEric Fiselier // cxa_guard_release. Specifically, that they leave the first byte with
4870ebeabfSEric Fiselier // the value 0 or 1 as specified by the ARM or Itanium specification.
testTests4970ebeabfSEric Fiselier static void test() {
5070ebeabfSEric Fiselier Tests tests;
5170ebeabfSEric Fiselier tests.test_acquire();
5270ebeabfSEric Fiselier tests.test_abort();
5370ebeabfSEric Fiselier tests.test_release();
5470ebeabfSEric Fiselier }
5570ebeabfSEric Fiselier
test_acquireTests5670ebeabfSEric Fiselier void test_acquire() {
5770ebeabfSEric Fiselier {
5870ebeabfSEric Fiselier reset();
5970ebeabfSEric Fiselier assert(first_byte() == 0);
6070ebeabfSEric Fiselier assert(impl.cxa_guard_acquire() == INIT_IS_PENDING);
6170ebeabfSEric Fiselier assert(first_byte() == 0);
6270ebeabfSEric Fiselier }
6370ebeabfSEric Fiselier {
6470ebeabfSEric Fiselier reset();
6570ebeabfSEric Fiselier assert(first_byte() == 0);
6670ebeabfSEric Fiselier assert(impl.cxa_guard_acquire() == INIT_IS_PENDING);
6770ebeabfSEric Fiselier impl.cxa_guard_release();
6870ebeabfSEric Fiselier assert(first_byte() == 1);
6970ebeabfSEric Fiselier assert(impl.cxa_guard_acquire() == INIT_IS_DONE);
7070ebeabfSEric Fiselier }
7170ebeabfSEric Fiselier }
7270ebeabfSEric Fiselier
test_releaseTests7370ebeabfSEric Fiselier void test_release() {
7470ebeabfSEric Fiselier {
7570ebeabfSEric Fiselier reset();
7670ebeabfSEric Fiselier assert(first_byte() == 0);
7770ebeabfSEric Fiselier assert(impl.cxa_guard_acquire() == INIT_IS_PENDING);
7870ebeabfSEric Fiselier assert(first_byte() == 0);
7970ebeabfSEric Fiselier impl.cxa_guard_release();
8070ebeabfSEric Fiselier assert(first_byte() == 1);
8170ebeabfSEric Fiselier }
8270ebeabfSEric Fiselier }
8370ebeabfSEric Fiselier
test_abortTests8470ebeabfSEric Fiselier void test_abort() {
8570ebeabfSEric Fiselier {
8670ebeabfSEric Fiselier reset();
8770ebeabfSEric Fiselier assert(first_byte() == 0);
8870ebeabfSEric Fiselier assert(impl.cxa_guard_acquire() == INIT_IS_PENDING);
8970ebeabfSEric Fiselier assert(first_byte() == 0);
9070ebeabfSEric Fiselier impl.cxa_guard_abort();
9170ebeabfSEric Fiselier assert(first_byte() == 0);
9270ebeabfSEric Fiselier assert(impl.cxa_guard_acquire() == INIT_IS_PENDING);
9370ebeabfSEric Fiselier assert(first_byte() == 0);
9470ebeabfSEric Fiselier }
9570ebeabfSEric Fiselier }
9670ebeabfSEric Fiselier };
9770ebeabfSEric Fiselier
9870ebeabfSEric Fiselier struct NopMutex {
lockNopMutex9970ebeabfSEric Fiselier bool lock() {
10070ebeabfSEric Fiselier assert(!is_locked);
10170ebeabfSEric Fiselier is_locked = true;
10270ebeabfSEric Fiselier return false;
10370ebeabfSEric Fiselier }
unlockNopMutex10470ebeabfSEric Fiselier bool unlock() {
10570ebeabfSEric Fiselier assert(is_locked);
10670ebeabfSEric Fiselier is_locked = false;
10770ebeabfSEric Fiselier return false;
10870ebeabfSEric Fiselier }
10970ebeabfSEric Fiselier
11070ebeabfSEric Fiselier private:
11170ebeabfSEric Fiselier bool is_locked = false;
11270ebeabfSEric Fiselier };
11327fd2f60SEric Fiselier NopMutex global_nop_mutex = {};
11470ebeabfSEric Fiselier
11570ebeabfSEric Fiselier struct NopCondVar {
broadcastNopCondVar11670ebeabfSEric Fiselier bool broadcast() { return false; }
waitNopCondVar11770ebeabfSEric Fiselier bool wait(NopMutex&) { return false; }
11870ebeabfSEric Fiselier };
11927fd2f60SEric Fiselier NopCondVar global_nop_cond = {};
12070ebeabfSEric Fiselier
NopFutexWait(int *,int)12170ebeabfSEric Fiselier void NopFutexWait(int*, int) { assert(false); }
NopFutexWake(int *)12270ebeabfSEric Fiselier void NopFutexWake(int*) { assert(false); }
MockGetThreadID()12370ebeabfSEric Fiselier uint32_t MockGetThreadID() { return 0; }
12470ebeabfSEric Fiselier
main(int,char **)125504bc07dSLouis Dionne int main(int, char**) {
12670ebeabfSEric Fiselier {
127*851bfc07SLouis Dionne #if defined(TEST_HAS_NO_THREADS)
12870ebeabfSEric Fiselier static_assert(CurrentImplementation == Implementation::NoThreads, "");
129f011a53cSDaniel McIntosh static_assert(std::is_same<SelectedImplementation, NoThreadsGuard>::value, "");
13070ebeabfSEric Fiselier #else
131e42eeb88SDaniel McIntosh static_assert(CurrentImplementation == Implementation::GlobalMutex, "");
132f011a53cSDaniel McIntosh static_assert(std::is_same<SelectedImplementation,
133f011a53cSDaniel McIntosh GlobalMutexGuard<LibcppMutex, LibcppCondVar, GlobalStatic<LibcppMutex>::instance,
134f011a53cSDaniel McIntosh GlobalStatic<LibcppCondVar>::instance>>::value,
13570ebeabfSEric Fiselier "");
13670ebeabfSEric Fiselier #endif
13770ebeabfSEric Fiselier }
13870ebeabfSEric Fiselier {
139*851bfc07SLouis Dionne #if (defined(__APPLE__) || defined(__linux__)) && !defined(TEST_HAS_NO_THREADS)
14070ebeabfSEric Fiselier assert(PlatformThreadID);
14170ebeabfSEric Fiselier #endif
1423601ee6cSDaniel McIntosh if (PlatformThreadID != nullptr) {
14370ebeabfSEric Fiselier assert(PlatformThreadID() != 0);
14470ebeabfSEric Fiselier assert(PlatformThreadID() == PlatformThreadID());
14570ebeabfSEric Fiselier }
14670ebeabfSEric Fiselier }
14770ebeabfSEric Fiselier {
148f011a53cSDaniel McIntosh Tests<uint32_t, NoThreadsGuard>::test();
149f011a53cSDaniel McIntosh Tests<uint64_t, NoThreadsGuard>::test();
15070ebeabfSEric Fiselier }
15170ebeabfSEric Fiselier {
152f011a53cSDaniel McIntosh using MutexImpl = GlobalMutexGuard<NopMutex, NopCondVar, global_nop_mutex, global_nop_cond, MockGetThreadID>;
15370ebeabfSEric Fiselier Tests<uint32_t, MutexImpl>::test();
15470ebeabfSEric Fiselier Tests<uint64_t, MutexImpl>::test();
15570ebeabfSEric Fiselier }
15670ebeabfSEric Fiselier {
157f011a53cSDaniel McIntosh using FutexImpl = FutexGuard<&NopFutexWait, &NopFutexWake, &MockGetThreadID>;
15870ebeabfSEric Fiselier Tests<uint32_t, FutexImpl>::test();
15970ebeabfSEric Fiselier Tests<uint64_t, FutexImpl>::test();
16070ebeabfSEric Fiselier }
161504bc07dSLouis Dionne
162504bc07dSLouis Dionne return 0;
16370ebeabfSEric Fiselier }
164