• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===-- atomic_test.cpp -----------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "tests/scudo_unit_test.h"
10 
11 #include "atomic_helpers.h"
12 
13 namespace scudo {
14 
15 template <typename T> struct ValAndMagic {
16   typename T::Type Magic0;
17   T A;
18   typename T::Type Magic1;
19 
20   static ValAndMagic<T> *Sink;
21 };
22 
23 template <typename T> ValAndMagic<T> *ValAndMagic<T>::Sink;
24 
25 template <typename T, memory_order LoadMO, memory_order StoreMO>
checkStoreLoad()26 void checkStoreLoad() {
27   typedef typename T::Type Type;
28   ValAndMagic<T> Val;
29   // Prevent the compiler from scalarizing the struct.
30   ValAndMagic<T>::Sink = &Val;
31   // Ensure that surrounding memory is not overwritten.
32   Val.Magic0 = Val.Magic1 = (Type)-3;
33   for (u64 I = 0; I < 100; I++) {
34     // Generate A value that occupies all bytes of the variable.
35     u64 V = I;
36     V |= V << 8;
37     V |= V << 16;
38     V |= V << 32;
39     Val.A.ValDoNotUse = (Type)V;
40     EXPECT_EQ(atomic_load(&Val.A, LoadMO), (Type)V);
41     Val.A.ValDoNotUse = (Type)-1;
42     atomic_store(&Val.A, (Type)V, StoreMO);
43     EXPECT_EQ(Val.A.ValDoNotUse, (Type)V);
44   }
45   EXPECT_EQ(Val.Magic0, (Type)-3);
46   EXPECT_EQ(Val.Magic1, (Type)-3);
47 }
48 
TEST(ScudoAtomicTest,AtomicStoreLoad)49 TEST(ScudoAtomicTest, AtomicStoreLoad) {
50   checkStoreLoad<atomic_u8, memory_order_relaxed, memory_order_relaxed>();
51   checkStoreLoad<atomic_u8, memory_order_consume, memory_order_relaxed>();
52   checkStoreLoad<atomic_u8, memory_order_acquire, memory_order_relaxed>();
53   checkStoreLoad<atomic_u8, memory_order_relaxed, memory_order_release>();
54   checkStoreLoad<atomic_u8, memory_order_seq_cst, memory_order_seq_cst>();
55 
56   checkStoreLoad<atomic_u16, memory_order_relaxed, memory_order_relaxed>();
57   checkStoreLoad<atomic_u16, memory_order_consume, memory_order_relaxed>();
58   checkStoreLoad<atomic_u16, memory_order_acquire, memory_order_relaxed>();
59   checkStoreLoad<atomic_u16, memory_order_relaxed, memory_order_release>();
60   checkStoreLoad<atomic_u16, memory_order_seq_cst, memory_order_seq_cst>();
61 
62   checkStoreLoad<atomic_u32, memory_order_relaxed, memory_order_relaxed>();
63   checkStoreLoad<atomic_u32, memory_order_consume, memory_order_relaxed>();
64   checkStoreLoad<atomic_u32, memory_order_acquire, memory_order_relaxed>();
65   checkStoreLoad<atomic_u32, memory_order_relaxed, memory_order_release>();
66   checkStoreLoad<atomic_u32, memory_order_seq_cst, memory_order_seq_cst>();
67 
68   checkStoreLoad<atomic_u64, memory_order_relaxed, memory_order_relaxed>();
69   checkStoreLoad<atomic_u64, memory_order_consume, memory_order_relaxed>();
70   checkStoreLoad<atomic_u64, memory_order_acquire, memory_order_relaxed>();
71   checkStoreLoad<atomic_u64, memory_order_relaxed, memory_order_release>();
72   checkStoreLoad<atomic_u64, memory_order_seq_cst, memory_order_seq_cst>();
73 
74   checkStoreLoad<atomic_uptr, memory_order_relaxed, memory_order_relaxed>();
75   checkStoreLoad<atomic_uptr, memory_order_consume, memory_order_relaxed>();
76   checkStoreLoad<atomic_uptr, memory_order_acquire, memory_order_relaxed>();
77   checkStoreLoad<atomic_uptr, memory_order_relaxed, memory_order_release>();
78   checkStoreLoad<atomic_uptr, memory_order_seq_cst, memory_order_seq_cst>();
79 }
80 
checkAtomicCompareExchange()81 template <typename T> void checkAtomicCompareExchange() {
82   typedef typename T::Type Type;
83   {
84     Type OldVal = 42;
85     Type NewVal = 24;
86     Type V = OldVal;
87     EXPECT_TRUE(atomic_compare_exchange_strong(
88         reinterpret_cast<T *>(&V), &OldVal, NewVal, memory_order_relaxed));
89     EXPECT_FALSE(atomic_compare_exchange_strong(
90         reinterpret_cast<T *>(&V), &OldVal, NewVal, memory_order_relaxed));
91     EXPECT_EQ(NewVal, OldVal);
92   }
93   {
94     Type OldVal = 42;
95     Type NewVal = 24;
96     Type V = OldVal;
97     EXPECT_TRUE(atomic_compare_exchange_weak(reinterpret_cast<T *>(&V), &OldVal,
98                                              NewVal, memory_order_relaxed));
99     EXPECT_FALSE(atomic_compare_exchange_weak(
100         reinterpret_cast<T *>(&V), &OldVal, NewVal, memory_order_relaxed));
101     EXPECT_EQ(NewVal, OldVal);
102   }
103 }
104 
TEST(ScudoAtomicTest,AtomicCompareExchangeTest)105 TEST(ScudoAtomicTest, AtomicCompareExchangeTest) {
106   checkAtomicCompareExchange<atomic_u8>();
107   checkAtomicCompareExchange<atomic_u16>();
108   checkAtomicCompareExchange<atomic_u32>();
109   checkAtomicCompareExchange<atomic_u64>();
110   checkAtomicCompareExchange<atomic_uptr>();
111 }
112 
113 } // namespace scudo
114