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