diff --git a/compiler-rt/lib/scudo/standalone/CMakeLists.txt b/compiler-rt/lib/scudo/standalone/CMakeLists.txt --- a/compiler-rt/lib/scudo/standalone/CMakeLists.txt +++ b/compiler-rt/lib/scudo/standalone/CMakeLists.txt @@ -61,6 +61,9 @@ bytemap.h checksum.h chunk.h + condition_variable.h + condition_variable_base.h + condition_variable_linux.h combined.h common.h flags_parser.h @@ -102,6 +105,7 @@ set(SCUDO_SOURCES checksum.cpp common.cpp + condition_variable_linux.cpp crc32_hw.cpp flags_parser.cpp flags.cpp diff --git a/compiler-rt/lib/scudo/standalone/allocator_config.h b/compiler-rt/lib/scudo/standalone/allocator_config.h --- a/compiler-rt/lib/scudo/standalone/allocator_config.h +++ b/compiler-rt/lib/scudo/standalone/allocator_config.h @@ -11,6 +11,7 @@ #include "combined.h" #include "common.h" +#include "condition_variable.h" #include "flags.h" #include "primary32.h" #include "primary64.h" @@ -82,6 +83,13 @@ // // Defines the minimal & maximal release interval that can be set. // static const s32 MinReleaseToOsIntervalMs = INT32_MIN; // static const s32 MaxReleaseToOsIntervalMs = INT32_MAX; +// +// // Use condition variable to shorten the waiting time of refillment of +// // freelist. Note that this depends on the implementation of condition +// // variable on each platform and the performance may vary so that it +// // doesn't guarantee a performance benefit. +// static const bool UseConditionVariable = false; +// using ConditionVariableT = ConditionVariableNoOP; // }; // // Defines the type of Primary allocator to use. // template using PrimaryT = SizeClassAllocator64; @@ -128,6 +136,8 @@ #endif static const s32 MinReleaseToOsIntervalMs = INT32_MIN; static const s32 MaxReleaseToOsIntervalMs = INT32_MAX; + static const bool UseConditionVariable = false; + using ConditionVariableT = ConditionVariableNoOP; }; #if SCUDO_CAN_USE_PRIMARY64 template using PrimaryT = SizeClassAllocator64; @@ -173,6 +183,8 @@ #endif static const s32 MinReleaseToOsIntervalMs = 1000; static const s32 MaxReleaseToOsIntervalMs = 1000; + static const bool UseConditionVariable = false; + using ConditionVariableT = ConditionVariableNoOP; }; #if SCUDO_CAN_USE_PRIMARY64 template using PrimaryT = SizeClassAllocator64; @@ -216,6 +228,8 @@ #endif static const s32 MinReleaseToOsIntervalMs = 1000; static const s32 MaxReleaseToOsIntervalMs = 1000; + static const bool UseConditionVariable = false; + using ConditionVariableT = ConditionVariableNoOP; }; #if SCUDO_CAN_USE_PRIMARY64 @@ -261,6 +275,8 @@ static const uptr CompactPtrScale = SCUDO_MIN_ALIGNMENT_LOG; static const s32 MinReleaseToOsIntervalMs = INT32_MIN; static const s32 MaxReleaseToOsIntervalMs = INT32_MAX; + static const bool UseConditionVariable = false; + using ConditionVariableT = ConditionVariableNoOP; }; template using PrimaryT = SizeClassAllocator64; @@ -285,6 +301,8 @@ static const uptr CompactPtrScale = SCUDO_MIN_ALIGNMENT_LOG; static const s32 MinReleaseToOsIntervalMs = INT32_MIN; static const s32 MaxReleaseToOsIntervalMs = INT32_MAX; + static const bool UseConditionVariable = false; + using ConditionVariableT = ConditionVariableNoOP; }; template using PrimaryT = SizeClassAllocator64; diff --git a/compiler-rt/lib/scudo/standalone/condition_variable.h b/compiler-rt/lib/scudo/standalone/condition_variable.h new file mode 100644 --- /dev/null +++ b/compiler-rt/lib/scudo/standalone/condition_variable.h @@ -0,0 +1,35 @@ +//===-- condition_variable.h ------------------------------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef SCUDO_CONDITION_VARIABLE_H_ +#define SCUDO_CONDITION_VARIABLE_H_ + +#include "condition_variable_base.h" + +#include "common.h" +#include "platform.h" + +#include "condition_variable_linux.h" + +namespace scudo { + +// A dummy implementation of default condition variable. Note that this is +// supposed to be only used for testing the control flows of paths with +// condition variable enabled. It's supposed to turn the sleeping into +// busy-waiting and all the functions should still work. +class ConditionVariableNoOP + : public ConditionVariableBase { +public: + void notifyAllImpl(UNUSED HybridMutex &M) REQUIRES(M) {} + + void waitImpl(UNUSED HybridMutex &M) REQUIRES(M) {} +}; + +} // namespace scudo + +#endif // SCUDO_CONDITION_VARIABLE_H_ diff --git a/compiler-rt/lib/scudo/standalone/condition_variable_base.h b/compiler-rt/lib/scudo/standalone/condition_variable_base.h new file mode 100644 --- /dev/null +++ b/compiler-rt/lib/scudo/standalone/condition_variable_base.h @@ -0,0 +1,57 @@ +//===-- condition_variable_base.h ------------------------------------*- C++ +//-*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef SCUDO_CONDITION_VARIABLE_BASE_H_ +#define SCUDO_CONDITION_VARIABLE_BASE_H_ + +#include "mutex.h" +#include "thread_annotations.h" + +namespace scudo { + +template class ConditionVariableBase { +public: + constexpr ConditionVariableBase() = default; + + void bindTestOnly(HybridMutex &Mutex) { +#if SCUDO_DEBUG + boundMutex = &Mutex; +#else + (void)Mutex; +#endif + } + + void notifyAll(HybridMutex &M) REQUIRES(M) { +#if SCUDO_DEBUG + CHECK_EQ(&M, boundMutex); +#endif + getDerived()->notifyAllImpl(M); + } + + void wait(HybridMutex &M) REQUIRES(M) { +#if SCUDO_DEBUG + CHECK_EQ(&M, boundMutex); +#endif + getDerived()->waitImpl(M); + } + +protected: + Derived *getDerived() { return static_cast(this); } + +#if SCUDO_DEBUG + // Because thread-safety analysis doesn't support pointer aliasing, we are not + // able to mark the proper annotations without false positive. Instead, we + // pass the lock and do the same-lock check separately. + HybridMutex *boundMutex = nullptr; +#endif +}; + +} // namespace scudo + +#endif // SCUDO_CONDITION_VARIABLE_BASE_H_ diff --git a/compiler-rt/lib/scudo/standalone/condition_variable_linux.h b/compiler-rt/lib/scudo/standalone/condition_variable_linux.h new file mode 100644 --- /dev/null +++ b/compiler-rt/lib/scudo/standalone/condition_variable_linux.h @@ -0,0 +1,42 @@ +//===-- condition_variable_linux.h ------------------------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef SCUDO_CONDITION_VARIABLE_LINUX_H_ +#define SCUDO_CONDITION_VARIABLE_LINUX_H_ + +#include "platform.h" + +#if SCUDO_LINUX + +#include "atomic_helpers.h" +#include "condition_variable_base.h" +#include "thread_annotations.h" + +namespace scudo { + +class ConditionVariableLinux + : public ConditionVariableBase { +public: + void notifyAllImpl(HybridMutex &M) REQUIRES(M); + + void waitImpl(HybridMutex &M) REQUIRES(M); + +private: + enum State : u32 { + AllAwoken, + Waiting, + }; + + atomic_u32 CurState = {}; +}; + +} // namespace scudo + +#endif // SCUDO_LINUX + +#endif // SCUDO_CONDITION_VARIABLE_LINUX_H_ diff --git a/compiler-rt/lib/scudo/standalone/condition_variable_linux.cpp b/compiler-rt/lib/scudo/standalone/condition_variable_linux.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/lib/scudo/standalone/condition_variable_linux.cpp @@ -0,0 +1,48 @@ +//===-- condition_variable_linux.cpp ----------------------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "platform.h" + +#if SCUDO_LINUX + +#include "condition_variable_linux.h" + +#include "atomic_helpers.h" + +#include +#include +#include +#include + +namespace scudo { + +void ConditionVariableLinux::notifyAllImpl(UNUSED HybridMutex &M) { + u32 V = atomic_exchange(&CurState, State::AllAwoken, memory_order_acq_rel); + + // TODO(chiahungduan): Move the waiters from the futex waiting queue + // `CurState` to futex waiting queue `M` so that the awoken threads won't be + // blocked again due to locked `M` by current thread. + if (V == State::Waiting) { + syscall(SYS_futex, reinterpret_cast(&CurState), FUTEX_WAKE_PRIVATE, + INT_MAX, nullptr, nullptr, 0); + } +} + +void ConditionVariableLinux::waitImpl(HybridMutex &M) { + atomic_exchange(&CurState, State::Waiting, memory_order_acq_rel); + + // TODO: Use ScopedUnlock when it's supported. + M.unlock(); + syscall(SYS_futex, reinterpret_cast(&CurState), FUTEX_WAIT_PRIVATE, + State::Waiting, nullptr, nullptr, 0); + M.lock(); +} + +} // namespace scudo + +#endif // SCUDO_LINUX diff --git a/compiler-rt/lib/scudo/standalone/primary64.h b/compiler-rt/lib/scudo/standalone/primary64.h --- a/compiler-rt/lib/scudo/standalone/primary64.h +++ b/compiler-rt/lib/scudo/standalone/primary64.h @@ -47,6 +47,7 @@ public: typedef typename Config::Primary::CompactPtrT CompactPtrT; typedef typename Config::Primary::SizeClassMap SizeClassMap; + typedef typename Config::Primary::ConditionVariableT ConditionVariableT; static const uptr CompactPtrScale = Config::Primary::CompactPtrScale; static const uptr GroupSizeLog = Config::Primary::GroupSizeLog; static const uptr GroupScale = GroupSizeLog - CompactPtrScale; @@ -117,6 +118,7 @@ for (uptr I = 0; I < NumClasses; I++) { RegionInfo *Region = getRegionInfo(I); + // The actual start of a region is offset by a random number of pages // when PrimaryEnableRandomOffset is set. Region->RegionBeg = @@ -139,6 +141,11 @@ } shuffle(RegionInfoArray, NumClasses, &Seed); + // The binding should be done after region shuffling so that it won't bind + // the FLLock from wrong region. + for (uptr I = 0; I < NumClasses; I++) + getRegionInfo(I)->FLLockCV.bindTestOnly(getRegionInfo(I)->FLLock); + setOption(Option::ReleaseInterval, static_cast(ReleaseToOsInterval)); } @@ -215,26 +222,26 @@ bool PrintStats = false; TransferBatch *B = nullptr; - while (true) { - // When two threads compete for `Region->MMLock`, we only want one of them - // does the populateFreeListAndPopBatch(). To avoid both of them doing - // that, always check the freelist before mapping new pages. - // - // TODO(chiahungduan): Use a condition variable so that we don't need to - // hold `Region->MMLock` here. - ScopedLock ML(Region->MMLock); - { - ScopedLock FL(Region->FLLock); - B = popBatchImpl(C, ClassId, Region); - if (LIKELY(B)) - return B; - } + if (Config::Primary::UseConditionVariable) { + B = popBatchWithCV(C, ClassId, Region, PrintStats); + } else { + while (true) { + // When two threads compete for `Region->MMLock`, we only want one of + // them does the populateFreeListAndPopBatch(). To avoid both of them + // doing that, always check the freelist before mapping new pages. + ScopedLock ML(Region->MMLock); + { + ScopedLock FL(Region->FLLock); + if ((B = popBatchImpl(C, ClassId, Region))) + break; + } - const bool RegionIsExhausted = Region->Exhausted; - if (!RegionIsExhausted) - B = populateFreeListAndPopBatch(C, ClassId, Region); - PrintStats = !RegionIsExhausted && Region->Exhausted; - break; + const bool RegionIsExhausted = Region->Exhausted; + if (!RegionIsExhausted) + B = populateFreeListAndPopBatch(C, ClassId, Region); + PrintStats = !RegionIsExhausted && Region->Exhausted; + break; + } } // Note that `getStats()` requires locking each region so we can't call it @@ -265,6 +272,8 @@ if (ClassId == SizeClassMap::BatchClassId) { ScopedLock L(Region->FLLock); pushBatchClassBlocks(Region, Array, Size); + if (Config::Primary::UseConditionVariable) + Region->FLLockCV.notifyAll(Region->FLLock); return; } @@ -289,6 +298,8 @@ { ScopedLock L(Region->FLLock); pushBlocksImpl(C, ClassId, Region, Array, Size, SameGroup); + if (Config::Primary::UseConditionVariable) + Region->FLLockCV.notifyAll(Region->FLLock); } } @@ -509,6 +520,7 @@ struct UnpaddedRegionInfo { // Mutex for operations on freelist HybridMutex FLLock; + ConditionVariableT FLLockCV GUARDED_BY(FLLock); // Mutex for memmap operations HybridMutex MMLock ACQUIRED_BEFORE(FLLock); // `RegionBeg` is initialized before thread creation and won't be changed. @@ -520,6 +532,7 @@ uptr TryReleaseThreshold GUARDED_BY(MMLock) = 0; ReleaseToOsInfo ReleaseInfo GUARDED_BY(MMLock) = {}; bool Exhausted GUARDED_BY(MMLock) = false; + bool isPopulatingFreeList GUARDED_BY(FLLock) = false; }; struct RegionInfo : UnpaddedRegionInfo { char Padding[SCUDO_CACHE_LINE_SIZE - @@ -802,6 +815,76 @@ InsertBlocks(Cur, Array + Size - Count, Count); } + TransferBatch *popBatchWithCV(CacheT *C, uptr ClassId, RegionInfo *Region, + bool &PrintStats) { + TransferBatch *B = nullptr; + + while (true) { + // We only expect one thread doing the freelist refillment and other + // threads will be waiting for either the completion of the + // `populateFreeListAndPopBatch()` or `pushBlocks()` called by other + // threads. + bool PopulateFreeList = false; + { + ScopedLock FL(Region->FLLock); + if (!Region->isPopulatingFreeList) { + Region->isPopulatingFreeList = true; + PopulateFreeList = true; + } + } + + if (PopulateFreeList) { + ScopedLock ML(Region->MMLock); + + const bool RegionIsExhausted = Region->Exhausted; + if (!RegionIsExhausted) + B = populateFreeListAndPopBatch(C, ClassId, Region); + PrintStats = !RegionIsExhausted && Region->Exhausted; + + { + // Before reacquiring the `FLLock`, the freelist may be used up again + // and some threads are waiting for the freelist refillment by the + // current thread. It's important to set + // `Region->isPopulatingFreeList` to false so the threads about to + // sleep will notice the status change. + ScopedLock FL(Region->FLLock); + Region->isPopulatingFreeList = false; + Region->FLLockCV.notifyAll(Region->FLLock); + } + + break; + } + + // At here, there are two preconditions to be met before waiting, + // 1. The freelist is empty. + // 2. Region->isPopulatingFreeList == true, i.e, someone is still doing + // `populateFreeListAndPopBatch()`. + // + // Note that it has the chance that freelist is empty but + // Region->isPopulatingFreeList == false because all the new populated + // blocks were used up right after the refillment. Therefore, we have to + // check if someone is still populating freelist. + ScopedLock FL(Region->FLLock); + if (LIKELY(B = popBatchImpl(C, ClassId, Region))) + break; + + if (!Region->isPopulatingFreeList) + continue; + + // Now the freelist is empty and someone's doing the refillment. We will + // wait until anyone refills the freelist or someone finishes doing + // `populateFreeListAndPopBatch()`. The refillment can be done by + // `populateFreeListAndPopBatch()`, `pushBlocks()`, + // `pushBatchClassBlocks()` and `mergeGroupsToReleaseBack()`. + Region->FLLockCV.wait(Region->FLLock); + + if (LIKELY(B = popBatchImpl(C, ClassId, Region))) + break; + } + + return B; + } + // Pop one TransferBatch from a BatchGroup. The BatchGroup with the smallest // group id will be considered first. // @@ -1451,6 +1534,8 @@ if (UNLIKELY(Idx + NeededSlots > MaxUnusedSize)) { ScopedLock L(BatchClassRegion->FLLock); pushBatchClassBlocks(BatchClassRegion, Blocks, Idx); + if (Config::Primary::UseConditionVariable) + BatchClassRegion->FLLockCV.notifyAll(BatchClassRegion->FLLock); Idx = 0; } Blocks[Idx++] = @@ -1486,6 +1571,8 @@ if (Idx != 0) { ScopedLock L(BatchClassRegion->FLLock); pushBatchClassBlocks(BatchClassRegion, Blocks, Idx); + if (Config::Primary::UseConditionVariable) + BatchClassRegion->FLLockCV.notifyAll(BatchClassRegion->FLLock); } if (SCUDO_DEBUG) { @@ -1495,6 +1582,9 @@ CHECK_LT(Prev->CompactPtrGroupBase, Cur->CompactPtrGroupBase); } } + + if (Config::Primary::UseConditionVariable) + Region->FLLockCV.notifyAll(Region->FLLock); } // TODO: `PrimaryBase` can be obtained from ReservedMemory. This needs to be diff --git a/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp b/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp --- a/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp +++ b/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp @@ -12,7 +12,9 @@ #include "allocator_config.h" #include "chunk.h" #include "combined.h" +#include "condition_variable.h" #include "mem_map.h" +#include "size_class_map.h" #include #include @@ -107,6 +109,52 @@ template using ScudoCombinedDeathTest = ScudoCombinedTest; +namespace scudo { +struct TestConditionVariableConfig { + static const bool MaySupportMemoryTagging = true; + template + using TSDRegistryT = + scudo::TSDRegistrySharedT; // Shared, max 8 TSDs. + + struct Primary { + using SizeClassMap = scudo::AndroidSizeClassMap; +#if SCUDO_CAN_USE_PRIMARY64 + static const scudo::uptr RegionSizeLog = 28U; + typedef scudo::u32 CompactPtrT; + static const scudo::uptr CompactPtrScale = SCUDO_MIN_ALIGNMENT_LOG; + static const scudo::uptr GroupSizeLog = 20U; + static const bool EnableRandomOffset = true; + static const scudo::uptr MapSizeIncrement = 1UL << 18; +#else + static const scudo::uptr RegionSizeLog = 18U; + static const scudo::uptr GroupSizeLog = 18U; + typedef scudo::uptr CompactPtrT; +#endif + static const scudo::s32 MinReleaseToOsIntervalMs = 1000; + static const scudo::s32 MaxReleaseToOsIntervalMs = 1000; + static const bool UseConditionVariable = true; +#if SCUDO_LINUX + using ConditionVariableT = scudo::ConditionVariableLinux; +#else + using ConditionVariableT = scudo::ConditionVariableNoOP; +#endif + }; +#if SCUDO_CAN_USE_PRIMARY64 + template + using PrimaryT = scudo::SizeClassAllocator64; +#else + template + using PrimaryT = scudo::SizeClassAllocator32; +#endif + + struct Secondary { + template + using CacheT = scudo::MapAllocatorNoCache; + }; + template using SecondaryT = scudo::MapAllocator; +}; +} // namespace scudo + #if SCUDO_FUCHSIA #define SCUDO_TYPED_TEST_ALL_TYPES(FIXTURE, NAME) \ SCUDO_TYPED_TEST_TYPE(FIXTURE, NAME, AndroidSvelteConfig) \ @@ -115,7 +163,8 @@ #define SCUDO_TYPED_TEST_ALL_TYPES(FIXTURE, NAME) \ SCUDO_TYPED_TEST_TYPE(FIXTURE, NAME, AndroidSvelteConfig) \ SCUDO_TYPED_TEST_TYPE(FIXTURE, NAME, DefaultConfig) \ - SCUDO_TYPED_TEST_TYPE(FIXTURE, NAME, AndroidConfig) + SCUDO_TYPED_TEST_TYPE(FIXTURE, NAME, AndroidConfig) \ + SCUDO_TYPED_TEST_TYPE(FIXTURE, NAME, TestConditionVariableConfig) #endif #define SCUDO_TYPED_TEST_TYPE(FIXTURE, NAME, TYPE) \ @@ -558,6 +607,8 @@ static const bool EnableRandomOffset = true; static const scudo::uptr MapSizeIncrement = 1UL << 18; static const scudo::uptr GroupSizeLog = 18; + static const bool UseConditionVariable = false; + using ConditionVariableT = scudo::ConditionVariableNoOP; }; template using PrimaryT = scudo::SizeClassAllocator64; diff --git a/compiler-rt/lib/scudo/standalone/tests/primary_test.cpp b/compiler-rt/lib/scudo/standalone/tests/primary_test.cpp --- a/compiler-rt/lib/scudo/standalone/tests/primary_test.cpp +++ b/compiler-rt/lib/scudo/standalone/tests/primary_test.cpp @@ -8,6 +8,7 @@ #include "tests/scudo_unit_test.h" +#include "condition_variable.h" #include "primary32.h" #include "primary64.h" #include "size_class_map.h" @@ -38,6 +39,8 @@ static const scudo::uptr CompactPtrScale = 0; static const bool EnableRandomOffset = true; static const scudo::uptr MapSizeIncrement = 1UL << 18; + static const bool UseConditionVariable = false; + using ConditionVariableT = scudo::ConditionVariableNoOP; }; }; @@ -59,6 +62,8 @@ static const scudo::uptr CompactPtrScale = 0; static const bool EnableRandomOffset = true; static const scudo::uptr MapSizeIncrement = 1UL << 18; + static const bool UseConditionVariable = false; + using ConditionVariableT = scudo::ConditionVariableNoOP; }; }; @@ -80,6 +85,8 @@ static const scudo::uptr CompactPtrScale = 0; static const bool EnableRandomOffset = true; static const scudo::uptr MapSizeIncrement = 1UL << 18; + static const bool UseConditionVariable = false; + using ConditionVariableT = scudo::ConditionVariableNoOP; }; }; @@ -101,6 +108,36 @@ typedef scudo::u32 CompactPtrT; static const bool EnableRandomOffset = true; static const scudo::uptr MapSizeIncrement = 1UL << 18; + static const bool UseConditionVariable = false; + using ConditionVariableT = scudo::ConditionVariableNoOP; + }; +}; + +// This is the only test config that enables the condition variable. +template struct TestConfig5 { + static const bool MaySupportMemoryTagging = true; + + struct Primary { + using SizeClassMap = SizeClassMapT; +#if defined(__mips__) + // Unable to allocate greater size on QEMU-user. + static const scudo::uptr RegionSizeLog = 23U; +#else + static const scudo::uptr RegionSizeLog = 24U; +#endif + static const scudo::s32 MinReleaseToOsIntervalMs = INT32_MIN; + static const scudo::s32 MaxReleaseToOsIntervalMs = INT32_MAX; + static const scudo::uptr CompactPtrScale = SCUDO_MIN_ALIGNMENT_LOG; + static const scudo::uptr GroupSizeLog = 18U; + typedef scudo::u32 CompactPtrT; + static const bool EnableRandomOffset = true; + static const scudo::uptr MapSizeIncrement = 1UL << 18; + static const bool UseConditionVariable = true; +#if SCUDO_LINUX + using ConditionVariableT = scudo::ConditionVariableLinux; +#else + using ConditionVariableT = scudo::ConditionVariableNoOP; +#endif }; }; @@ -142,7 +179,8 @@ SCUDO_TYPED_TEST_TYPE(FIXTURE, NAME, TestConfig1) \ SCUDO_TYPED_TEST_TYPE(FIXTURE, NAME, TestConfig2) \ SCUDO_TYPED_TEST_TYPE(FIXTURE, NAME, TestConfig3) \ - SCUDO_TYPED_TEST_TYPE(FIXTURE, NAME, TestConfig4) + SCUDO_TYPED_TEST_TYPE(FIXTURE, NAME, TestConfig4) \ + SCUDO_TYPED_TEST_TYPE(FIXTURE, NAME, TestConfig5) #endif #define SCUDO_TYPED_TEST_TYPE(FIXTURE, NAME, TYPE) \ @@ -199,6 +237,8 @@ static const bool EnableRandomOffset = true; static const scudo::uptr MapSizeIncrement = 1UL << 18; static const scudo::uptr GroupSizeLog = 20U; + static const bool UseConditionVariable = false; + using ConditionVariableT = scudo::ConditionVariableNoOP; }; };