xref: /aosp_15_r20/external/cronet/base/atomicops_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2011 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "base/atomicops.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <stdint.h>
8*6777b538SAndroid Build Coastguard Worker #include <string.h>
9*6777b538SAndroid Build Coastguard Worker #include <type_traits>
10*6777b538SAndroid Build Coastguard Worker 
11*6777b538SAndroid Build Coastguard Worker #include "testing/gtest/include/gtest/gtest.h"
12*6777b538SAndroid Build Coastguard Worker 
13*6777b538SAndroid Build Coastguard Worker template <class AtomicType>
TestAtomicIncrement()14*6777b538SAndroid Build Coastguard Worker static void TestAtomicIncrement() {
15*6777b538SAndroid Build Coastguard Worker   // For now, we just test single threaded execution
16*6777b538SAndroid Build Coastguard Worker 
17*6777b538SAndroid Build Coastguard Worker   // use a guard value to make sure the NoBarrier_AtomicIncrement doesn't go
18*6777b538SAndroid Build Coastguard Worker   // outside the expected address bounds.  This is in particular to
19*6777b538SAndroid Build Coastguard Worker   // test that some future change to the asm code doesn't cause the
20*6777b538SAndroid Build Coastguard Worker   // 32-bit NoBarrier_AtomicIncrement doesn't do the wrong thing on 64-bit
21*6777b538SAndroid Build Coastguard Worker   // machines.
22*6777b538SAndroid Build Coastguard Worker   struct {
23*6777b538SAndroid Build Coastguard Worker     AtomicType prev_word;
24*6777b538SAndroid Build Coastguard Worker     AtomicType count;
25*6777b538SAndroid Build Coastguard Worker     AtomicType next_word;
26*6777b538SAndroid Build Coastguard Worker   } s;
27*6777b538SAndroid Build Coastguard Worker 
28*6777b538SAndroid Build Coastguard Worker   AtomicType prev_word_value, next_word_value;
29*6777b538SAndroid Build Coastguard Worker   memset(&prev_word_value, 0xFF, sizeof(AtomicType));
30*6777b538SAndroid Build Coastguard Worker   memset(&next_word_value, 0xEE, sizeof(AtomicType));
31*6777b538SAndroid Build Coastguard Worker 
32*6777b538SAndroid Build Coastguard Worker   s.prev_word = prev_word_value;
33*6777b538SAndroid Build Coastguard Worker   s.count = 0;
34*6777b538SAndroid Build Coastguard Worker   s.next_word = next_word_value;
35*6777b538SAndroid Build Coastguard Worker 
36*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 1), 1);
37*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(s.count, 1);
38*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(s.prev_word, prev_word_value);
39*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(s.next_word, next_word_value);
40*6777b538SAndroid Build Coastguard Worker 
41*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 2), 3);
42*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(s.count, 3);
43*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(s.prev_word, prev_word_value);
44*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(s.next_word, next_word_value);
45*6777b538SAndroid Build Coastguard Worker 
46*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 3), 6);
47*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(s.count, 6);
48*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(s.prev_word, prev_word_value);
49*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(s.next_word, next_word_value);
50*6777b538SAndroid Build Coastguard Worker 
51*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -3), 3);
52*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(s.count, 3);
53*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(s.prev_word, prev_word_value);
54*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(s.next_word, next_word_value);
55*6777b538SAndroid Build Coastguard Worker 
56*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -2), 1);
57*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(s.count, 1);
58*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(s.prev_word, prev_word_value);
59*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(s.next_word, next_word_value);
60*6777b538SAndroid Build Coastguard Worker 
61*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -1), 0);
62*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(s.count, 0);
63*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(s.prev_word, prev_word_value);
64*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(s.next_word, next_word_value);
65*6777b538SAndroid Build Coastguard Worker 
66*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -1), -1);
67*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(s.count, -1);
68*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(s.prev_word, prev_word_value);
69*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(s.next_word, next_word_value);
70*6777b538SAndroid Build Coastguard Worker 
71*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -4), -5);
72*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(s.count, -5);
73*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(s.prev_word, prev_word_value);
74*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(s.next_word, next_word_value);
75*6777b538SAndroid Build Coastguard Worker 
76*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 5), 0);
77*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(s.count, 0);
78*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(s.prev_word, prev_word_value);
79*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(s.next_word, next_word_value);
80*6777b538SAndroid Build Coastguard Worker }
81*6777b538SAndroid Build Coastguard Worker 
82*6777b538SAndroid Build Coastguard Worker 
83*6777b538SAndroid Build Coastguard Worker #define NUM_BITS(T) (sizeof(T) * 8)
84*6777b538SAndroid Build Coastguard Worker 
85*6777b538SAndroid Build Coastguard Worker 
86*6777b538SAndroid Build Coastguard Worker template <class AtomicType>
TestCompareAndSwap()87*6777b538SAndroid Build Coastguard Worker static void TestCompareAndSwap() {
88*6777b538SAndroid Build Coastguard Worker   AtomicType value = 0;
89*6777b538SAndroid Build Coastguard Worker   AtomicType prev = base::subtle::NoBarrier_CompareAndSwap(&value, 0, 1);
90*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(1, value);
91*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(0, prev);
92*6777b538SAndroid Build Coastguard Worker 
93*6777b538SAndroid Build Coastguard Worker   // Verify that CAS will *not* change "value" if it doesn't match the
94*6777b538SAndroid Build Coastguard Worker   // expected  number. CAS will always return the actual value of the
95*6777b538SAndroid Build Coastguard Worker   // variable from before any change.
96*6777b538SAndroid Build Coastguard Worker   AtomicType fail = base::subtle::NoBarrier_CompareAndSwap(&value, 0, 2);
97*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(1, value);
98*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(1, fail);
99*6777b538SAndroid Build Coastguard Worker 
100*6777b538SAndroid Build Coastguard Worker   // Use test value that has non-zero bits in both halves, more for testing
101*6777b538SAndroid Build Coastguard Worker   // 64-bit implementation on 32-bit platforms.
102*6777b538SAndroid Build Coastguard Worker   const AtomicType k_test_val = (static_cast<uint64_t>(1) <<
103*6777b538SAndroid Build Coastguard Worker                                  (NUM_BITS(AtomicType) - 2)) + 11;
104*6777b538SAndroid Build Coastguard Worker   value = k_test_val;
105*6777b538SAndroid Build Coastguard Worker   prev = base::subtle::NoBarrier_CompareAndSwap(&value, 0, 5);
106*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(k_test_val, value);
107*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(k_test_val, prev);
108*6777b538SAndroid Build Coastguard Worker 
109*6777b538SAndroid Build Coastguard Worker   value = k_test_val;
110*6777b538SAndroid Build Coastguard Worker   prev = base::subtle::NoBarrier_CompareAndSwap(&value, k_test_val, 5);
111*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(5, value);
112*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(k_test_val, prev);
113*6777b538SAndroid Build Coastguard Worker }
114*6777b538SAndroid Build Coastguard Worker 
115*6777b538SAndroid Build Coastguard Worker 
116*6777b538SAndroid Build Coastguard Worker template <class AtomicType>
TestAtomicExchange()117*6777b538SAndroid Build Coastguard Worker static void TestAtomicExchange() {
118*6777b538SAndroid Build Coastguard Worker   AtomicType value = 0;
119*6777b538SAndroid Build Coastguard Worker   AtomicType new_value = base::subtle::NoBarrier_AtomicExchange(&value, 1);
120*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(1, value);
121*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(0, new_value);
122*6777b538SAndroid Build Coastguard Worker 
123*6777b538SAndroid Build Coastguard Worker   // Use test value that has non-zero bits in both halves, more for testing
124*6777b538SAndroid Build Coastguard Worker   // 64-bit implementation on 32-bit platforms.
125*6777b538SAndroid Build Coastguard Worker   const AtomicType k_test_val = (static_cast<uint64_t>(1) <<
126*6777b538SAndroid Build Coastguard Worker                                  (NUM_BITS(AtomicType) - 2)) + 11;
127*6777b538SAndroid Build Coastguard Worker   value = k_test_val;
128*6777b538SAndroid Build Coastguard Worker   new_value = base::subtle::NoBarrier_AtomicExchange(&value, k_test_val);
129*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(k_test_val, value);
130*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(k_test_val, new_value);
131*6777b538SAndroid Build Coastguard Worker 
132*6777b538SAndroid Build Coastguard Worker   value = k_test_val;
133*6777b538SAndroid Build Coastguard Worker   new_value = base::subtle::NoBarrier_AtomicExchange(&value, 5);
134*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(5, value);
135*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(k_test_val, new_value);
136*6777b538SAndroid Build Coastguard Worker }
137*6777b538SAndroid Build Coastguard Worker 
138*6777b538SAndroid Build Coastguard Worker 
139*6777b538SAndroid Build Coastguard Worker template <class AtomicType>
TestAtomicIncrementBounds()140*6777b538SAndroid Build Coastguard Worker static void TestAtomicIncrementBounds() {
141*6777b538SAndroid Build Coastguard Worker   // Test at rollover boundary between int_max and int_min
142*6777b538SAndroid Build Coastguard Worker   AtomicType test_val = (static_cast<uint64_t>(1) <<
143*6777b538SAndroid Build Coastguard Worker                          (NUM_BITS(AtomicType) - 1));
144*6777b538SAndroid Build Coastguard Worker   AtomicType value = -1 ^ test_val;
145*6777b538SAndroid Build Coastguard Worker   AtomicType new_value = base::subtle::NoBarrier_AtomicIncrement(&value, 1);
146*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(test_val, value);
147*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(value, new_value);
148*6777b538SAndroid Build Coastguard Worker 
149*6777b538SAndroid Build Coastguard Worker   base::subtle::NoBarrier_AtomicIncrement(&value, -1);
150*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(-1 ^ test_val, value);
151*6777b538SAndroid Build Coastguard Worker 
152*6777b538SAndroid Build Coastguard Worker   // Test at 32-bit boundary for 64-bit atomic type.
153*6777b538SAndroid Build Coastguard Worker   test_val = static_cast<uint64_t>(1) << (NUM_BITS(AtomicType) / 2);
154*6777b538SAndroid Build Coastguard Worker   value = test_val - 1;
155*6777b538SAndroid Build Coastguard Worker   new_value = base::subtle::NoBarrier_AtomicIncrement(&value, 1);
156*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(test_val, value);
157*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(value, new_value);
158*6777b538SAndroid Build Coastguard Worker 
159*6777b538SAndroid Build Coastguard Worker   base::subtle::NoBarrier_AtomicIncrement(&value, -1);
160*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(test_val - 1, value);
161*6777b538SAndroid Build Coastguard Worker }
162*6777b538SAndroid Build Coastguard Worker 
163*6777b538SAndroid Build Coastguard Worker // Return an AtomicType with the value 0xa5a5a5..
164*6777b538SAndroid Build Coastguard Worker template <class AtomicType>
TestFillValue()165*6777b538SAndroid Build Coastguard Worker static AtomicType TestFillValue() {
166*6777b538SAndroid Build Coastguard Worker   AtomicType val = 0;
167*6777b538SAndroid Build Coastguard Worker   memset(&val, 0xa5, sizeof(AtomicType));
168*6777b538SAndroid Build Coastguard Worker   return val;
169*6777b538SAndroid Build Coastguard Worker }
170*6777b538SAndroid Build Coastguard Worker 
171*6777b538SAndroid Build Coastguard Worker // This is a simple sanity check that values are correct. Not testing
172*6777b538SAndroid Build Coastguard Worker // atomicity
173*6777b538SAndroid Build Coastguard Worker template <class AtomicType>
TestStore()174*6777b538SAndroid Build Coastguard Worker static void TestStore() {
175*6777b538SAndroid Build Coastguard Worker   const AtomicType kVal1 = TestFillValue<AtomicType>();
176*6777b538SAndroid Build Coastguard Worker   const AtomicType kVal2 = static_cast<AtomicType>(-1);
177*6777b538SAndroid Build Coastguard Worker 
178*6777b538SAndroid Build Coastguard Worker   AtomicType value;
179*6777b538SAndroid Build Coastguard Worker 
180*6777b538SAndroid Build Coastguard Worker   if constexpr (std::is_same_v<AtomicType, base::subtle::Atomic32>) {
181*6777b538SAndroid Build Coastguard Worker     base::subtle::NoBarrier_Store(&value, kVal1);
182*6777b538SAndroid Build Coastguard Worker     EXPECT_EQ(kVal1, value);
183*6777b538SAndroid Build Coastguard Worker     base::subtle::NoBarrier_Store(&value, kVal2);
184*6777b538SAndroid Build Coastguard Worker     EXPECT_EQ(kVal2, value);
185*6777b538SAndroid Build Coastguard Worker   }
186*6777b538SAndroid Build Coastguard Worker 
187*6777b538SAndroid Build Coastguard Worker   base::subtle::Release_Store(&value, kVal1);
188*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(kVal1, value);
189*6777b538SAndroid Build Coastguard Worker   base::subtle::Release_Store(&value, kVal2);
190*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(kVal2, value);
191*6777b538SAndroid Build Coastguard Worker }
192*6777b538SAndroid Build Coastguard Worker 
193*6777b538SAndroid Build Coastguard Worker // This is a simple sanity check that values are correct. Not testing
194*6777b538SAndroid Build Coastguard Worker // atomicity
195*6777b538SAndroid Build Coastguard Worker template <class AtomicType>
TestLoad()196*6777b538SAndroid Build Coastguard Worker static void TestLoad() {
197*6777b538SAndroid Build Coastguard Worker   const AtomicType kVal1 = TestFillValue<AtomicType>();
198*6777b538SAndroid Build Coastguard Worker   const AtomicType kVal2 = static_cast<AtomicType>(-1);
199*6777b538SAndroid Build Coastguard Worker 
200*6777b538SAndroid Build Coastguard Worker   AtomicType value;
201*6777b538SAndroid Build Coastguard Worker 
202*6777b538SAndroid Build Coastguard Worker   value = kVal1;
203*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(kVal1, base::subtle::NoBarrier_Load(&value));
204*6777b538SAndroid Build Coastguard Worker   value = kVal2;
205*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(kVal2, base::subtle::NoBarrier_Load(&value));
206*6777b538SAndroid Build Coastguard Worker 
207*6777b538SAndroid Build Coastguard Worker   value = kVal1;
208*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(kVal1, base::subtle::Acquire_Load(&value));
209*6777b538SAndroid Build Coastguard Worker   value = kVal2;
210*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(kVal2, base::subtle::Acquire_Load(&value));
211*6777b538SAndroid Build Coastguard Worker }
212*6777b538SAndroid Build Coastguard Worker 
TEST(AtomicOpsTest,Inc)213*6777b538SAndroid Build Coastguard Worker TEST(AtomicOpsTest, Inc) {
214*6777b538SAndroid Build Coastguard Worker   TestAtomicIncrement<base::subtle::Atomic32>();
215*6777b538SAndroid Build Coastguard Worker   TestAtomicIncrement<base::subtle::AtomicWord>();
216*6777b538SAndroid Build Coastguard Worker }
217*6777b538SAndroid Build Coastguard Worker 
TEST(AtomicOpsTest,CompareAndSwap)218*6777b538SAndroid Build Coastguard Worker TEST(AtomicOpsTest, CompareAndSwap) {
219*6777b538SAndroid Build Coastguard Worker   TestCompareAndSwap<base::subtle::Atomic32>();
220*6777b538SAndroid Build Coastguard Worker   TestCompareAndSwap<base::subtle::AtomicWord>();
221*6777b538SAndroid Build Coastguard Worker }
222*6777b538SAndroid Build Coastguard Worker 
TEST(AtomicOpsTest,Exchange)223*6777b538SAndroid Build Coastguard Worker TEST(AtomicOpsTest, Exchange) {
224*6777b538SAndroid Build Coastguard Worker   TestAtomicExchange<base::subtle::Atomic32>();
225*6777b538SAndroid Build Coastguard Worker   TestAtomicExchange<base::subtle::AtomicWord>();
226*6777b538SAndroid Build Coastguard Worker }
227*6777b538SAndroid Build Coastguard Worker 
TEST(AtomicOpsTest,IncrementBounds)228*6777b538SAndroid Build Coastguard Worker TEST(AtomicOpsTest, IncrementBounds) {
229*6777b538SAndroid Build Coastguard Worker   TestAtomicIncrementBounds<base::subtle::Atomic32>();
230*6777b538SAndroid Build Coastguard Worker   TestAtomicIncrementBounds<base::subtle::AtomicWord>();
231*6777b538SAndroid Build Coastguard Worker }
232*6777b538SAndroid Build Coastguard Worker 
TEST(AtomicOpsTest,Store)233*6777b538SAndroid Build Coastguard Worker TEST(AtomicOpsTest, Store) {
234*6777b538SAndroid Build Coastguard Worker   TestStore<base::subtle::Atomic32>();
235*6777b538SAndroid Build Coastguard Worker   TestStore<base::subtle::AtomicWord>();
236*6777b538SAndroid Build Coastguard Worker }
237*6777b538SAndroid Build Coastguard Worker 
TEST(AtomicOpsTest,Load)238*6777b538SAndroid Build Coastguard Worker TEST(AtomicOpsTest, Load) {
239*6777b538SAndroid Build Coastguard Worker   TestLoad<base::subtle::Atomic32>();
240*6777b538SAndroid Build Coastguard Worker   TestLoad<base::subtle::AtomicWord>();
241*6777b538SAndroid Build Coastguard Worker }
242