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