//===-- atomic_test.cc ------------------------------------------*- 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 "scudo/standalone/atomic_helpers.h" #include "gtest/gtest.h" namespace scudo { template struct ValAndMagic { typename T::Type Magic0; T A; typename T::Type Magic1; static ValAndMagic *Sink; }; template ValAndMagic *ValAndMagic::Sink; template void checkStoreLoad() { typedef typename T::Type Type; ValAndMagic Val; // Prevent the compiler from scalarizing the struct. ValAndMagic::Sink = &Val; // Ensure that surrounding memory is not overwritten. Val.Magic0 = Val.Magic1 = (Type)-3; for (u64 I = 0; I < 100; I++) { // Generate A value that occupies all bytes of the variable. u64 V = I; V |= V << 8; V |= V << 16; V |= V << 32; Val.A.ValDoNotUse = (Type)V; EXPECT_EQ(atomic_load(&Val.A, LoadMO), (Type)V); Val.A.ValDoNotUse = (Type)-1; atomic_store(&Val.A, (Type)V, StoreMO); EXPECT_EQ(Val.A.ValDoNotUse, (Type)V); } EXPECT_EQ(Val.Magic0, (Type)-3); EXPECT_EQ(Val.Magic1, (Type)-3); } TEST(ScudoAtomicTest, AtomicStoreLoad) { checkStoreLoad(); checkStoreLoad(); checkStoreLoad(); checkStoreLoad(); checkStoreLoad(); checkStoreLoad(); checkStoreLoad(); checkStoreLoad(); checkStoreLoad(); checkStoreLoad(); checkStoreLoad(); checkStoreLoad(); checkStoreLoad(); checkStoreLoad(); checkStoreLoad(); checkStoreLoad(); checkStoreLoad(); checkStoreLoad(); checkStoreLoad(); checkStoreLoad(); checkStoreLoad(); checkStoreLoad(); checkStoreLoad(); checkStoreLoad(); checkStoreLoad(); } template void checkAtomicCompareExchange() { typedef typename T::Type Type; { Type OldVal = 42; Type NewVal = 24; Type V = OldVal; EXPECT_TRUE(atomic_compare_exchange_strong( reinterpret_cast(&V), &OldVal, NewVal, memory_order_relaxed)); EXPECT_FALSE(atomic_compare_exchange_strong( reinterpret_cast(&V), &OldVal, NewVal, memory_order_relaxed)); EXPECT_EQ(NewVal, OldVal); } { Type OldVal = 42; Type NewVal = 24; Type V = OldVal; EXPECT_TRUE(atomic_compare_exchange_weak(reinterpret_cast(&V), &OldVal, NewVal, memory_order_relaxed)); EXPECT_FALSE(atomic_compare_exchange_weak( reinterpret_cast(&V), &OldVal, NewVal, memory_order_relaxed)); EXPECT_EQ(NewVal, OldVal); } } TEST(ScudoAtomicTest, AtomicCompareExchangeTest) { checkAtomicCompareExchange(); checkAtomicCompareExchange(); checkAtomicCompareExchange(); checkAtomicCompareExchange(); checkAtomicCompareExchange(); } } // namespace scudo