102 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			102 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===-- atomic_test.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 "tests/scudo_unit_test.h"
 | |
| 
 | |
| #include "atomic_helpers.h"
 | |
| 
 | |
| namespace scudo {
 | |
| 
 | |
| template <typename T> struct ValAndMagic {
 | |
|   typename T::Type Magic0;
 | |
|   T A;
 | |
|   typename T::Type Magic1;
 | |
| 
 | |
|   static ValAndMagic<T> *Sink;
 | |
| };
 | |
| 
 | |
| template <typename T> ValAndMagic<T> *ValAndMagic<T>::Sink;
 | |
| 
 | |
| template <typename T, memory_order LoadMO, memory_order StoreMO>
 | |
| void checkStoreLoad() {
 | |
|   typedef typename T::Type Type;
 | |
|   ValAndMagic<T> Val;
 | |
|   // Prevent the compiler from scalarizing the struct.
 | |
|   ValAndMagic<T>::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<atomic_u8, memory_order_relaxed, memory_order_relaxed>();
 | |
|   checkStoreLoad<atomic_u8, memory_order_consume, memory_order_relaxed>();
 | |
|   checkStoreLoad<atomic_u8, memory_order_acquire, memory_order_relaxed>();
 | |
|   checkStoreLoad<atomic_u8, memory_order_relaxed, memory_order_release>();
 | |
|   checkStoreLoad<atomic_u8, memory_order_seq_cst, memory_order_seq_cst>();
 | |
| 
 | |
|   checkStoreLoad<atomic_u16, memory_order_relaxed, memory_order_relaxed>();
 | |
|   checkStoreLoad<atomic_u16, memory_order_consume, memory_order_relaxed>();
 | |
|   checkStoreLoad<atomic_u16, memory_order_acquire, memory_order_relaxed>();
 | |
|   checkStoreLoad<atomic_u16, memory_order_relaxed, memory_order_release>();
 | |
|   checkStoreLoad<atomic_u16, memory_order_seq_cst, memory_order_seq_cst>();
 | |
| 
 | |
|   checkStoreLoad<atomic_u32, memory_order_relaxed, memory_order_relaxed>();
 | |
|   checkStoreLoad<atomic_u32, memory_order_consume, memory_order_relaxed>();
 | |
|   checkStoreLoad<atomic_u32, memory_order_acquire, memory_order_relaxed>();
 | |
|   checkStoreLoad<atomic_u32, memory_order_relaxed, memory_order_release>();
 | |
|   checkStoreLoad<atomic_u32, memory_order_seq_cst, memory_order_seq_cst>();
 | |
| 
 | |
|   checkStoreLoad<atomic_u64, memory_order_relaxed, memory_order_relaxed>();
 | |
|   checkStoreLoad<atomic_u64, memory_order_consume, memory_order_relaxed>();
 | |
|   checkStoreLoad<atomic_u64, memory_order_acquire, memory_order_relaxed>();
 | |
|   checkStoreLoad<atomic_u64, memory_order_relaxed, memory_order_release>();
 | |
|   checkStoreLoad<atomic_u64, memory_order_seq_cst, memory_order_seq_cst>();
 | |
| 
 | |
|   checkStoreLoad<atomic_uptr, memory_order_relaxed, memory_order_relaxed>();
 | |
|   checkStoreLoad<atomic_uptr, memory_order_consume, memory_order_relaxed>();
 | |
|   checkStoreLoad<atomic_uptr, memory_order_acquire, memory_order_relaxed>();
 | |
|   checkStoreLoad<atomic_uptr, memory_order_relaxed, memory_order_release>();
 | |
|   checkStoreLoad<atomic_uptr, memory_order_seq_cst, memory_order_seq_cst>();
 | |
| }
 | |
| 
 | |
| template <typename T> void checkAtomicCompareExchange() {
 | |
|   typedef typename T::Type Type;
 | |
|   Type OldVal = 42;
 | |
|   Type NewVal = 24;
 | |
|   Type V = OldVal;
 | |
|   EXPECT_TRUE(atomic_compare_exchange_strong(reinterpret_cast<T *>(&V), &OldVal,
 | |
|                                              NewVal, memory_order_relaxed));
 | |
|   EXPECT_FALSE(atomic_compare_exchange_strong(
 | |
|       reinterpret_cast<T *>(&V), &OldVal, NewVal, memory_order_relaxed));
 | |
|   EXPECT_EQ(NewVal, OldVal);
 | |
| }
 | |
| 
 | |
| TEST(ScudoAtomicTest, AtomicCompareExchangeTest) {
 | |
|   checkAtomicCompareExchange<atomic_u8>();
 | |
|   checkAtomicCompareExchange<atomic_u16>();
 | |
|   checkAtomicCompareExchange<atomic_u32>();
 | |
|   checkAtomicCompareExchange<atomic_u64>();
 | |
|   checkAtomicCompareExchange<atomic_uptr>();
 | |
| }
 | |
| 
 | |
| } // namespace scudo
 |