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> |
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 | |
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 | |
81 | template <typename T> void checkAtomicCompareExchange() { |
82 | typedef typename T::Type Type; |
83 | Type OldVal = 42; |
84 | Type NewVal = 24; |
85 | Type V = OldVal; |
86 | EXPECT_TRUE(atomic_compare_exchange_strong(reinterpret_cast<T *>(&V), &OldVal, |
87 | NewVal, memory_order_relaxed)); |
88 | EXPECT_FALSE(atomic_compare_exchange_strong( |
89 | reinterpret_cast<T *>(&V), &OldVal, NewVal, memory_order_relaxed)); |
90 | EXPECT_EQ(NewVal, OldVal); |
91 | } |
92 | |
93 | TEST(ScudoAtomicTest, AtomicCompareExchangeTest) { |
94 | checkAtomicCompareExchange<atomic_u8>(); |
95 | checkAtomicCompareExchange<atomic_u16>(); |
96 | checkAtomicCompareExchange<atomic_u32>(); |
97 | checkAtomicCompareExchange<atomic_u64>(); |
98 | checkAtomicCompareExchange<atomic_uptr>(); |
99 | } |
100 | |
101 | } // namespace scudo |
102 | |