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 <string.h> 8 9 #include "base/port.h" 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 // Use test value that has non-zero bits in both halves, more for testing 93 // 64-bit implementation on 32-bit platforms. 94 const AtomicType k_test_val = (GG_ULONGLONG(1) << 95 (NUM_BITS(AtomicType) - 2)) + 11; 96 value = k_test_val; 97 prev = base::subtle::NoBarrier_CompareAndSwap(&value, 0, 5); 98 EXPECT_EQ(k_test_val, value); 99 EXPECT_EQ(k_test_val, prev); 100 101 value = k_test_val; 102 prev = base::subtle::NoBarrier_CompareAndSwap(&value, k_test_val, 5); 103 EXPECT_EQ(5, value); 104 EXPECT_EQ(k_test_val, prev); 105 } 106 107 108 template <class AtomicType> 109 static void TestAtomicExchange() { 110 AtomicType value = 0; 111 AtomicType new_value = base::subtle::NoBarrier_AtomicExchange(&value, 1); 112 EXPECT_EQ(1, value); 113 EXPECT_EQ(0, new_value); 114 115 // Use test value that has non-zero bits in both halves, more for testing 116 // 64-bit implementation on 32-bit platforms. 117 const AtomicType k_test_val = (GG_ULONGLONG(1) << 118 (NUM_BITS(AtomicType) - 2)) + 11; 119 value = k_test_val; 120 new_value = base::subtle::NoBarrier_AtomicExchange(&value, k_test_val); 121 EXPECT_EQ(k_test_val, value); 122 EXPECT_EQ(k_test_val, new_value); 123 124 value = k_test_val; 125 new_value = base::subtle::NoBarrier_AtomicExchange(&value, 5); 126 EXPECT_EQ(5, value); 127 EXPECT_EQ(k_test_val, new_value); 128 } 129 130 131 template <class AtomicType> 132 static void TestAtomicIncrementBounds() { 133 // Test at rollover boundary between int_max and int_min 134 AtomicType test_val = (GG_ULONGLONG(1) << 135 (NUM_BITS(AtomicType) - 1)); 136 AtomicType value = -1 ^ test_val; 137 AtomicType new_value = base::subtle::NoBarrier_AtomicIncrement(&value, 1); 138 EXPECT_EQ(test_val, value); 139 EXPECT_EQ(value, new_value); 140 141 base::subtle::NoBarrier_AtomicIncrement(&value, -1); 142 EXPECT_EQ(-1 ^ test_val, value); 143 144 // Test at 32-bit boundary for 64-bit atomic type. 145 test_val = GG_ULONGLONG(1) << (NUM_BITS(AtomicType) / 2); 146 value = test_val - 1; 147 new_value = base::subtle::NoBarrier_AtomicIncrement(&value, 1); 148 EXPECT_EQ(test_val, value); 149 EXPECT_EQ(value, new_value); 150 151 base::subtle::NoBarrier_AtomicIncrement(&value, -1); 152 EXPECT_EQ(test_val - 1, value); 153 } 154 155 // Return an AtomicType with the value 0xa5a5a5.. 156 template <class AtomicType> 157 static AtomicType TestFillValue() { 158 AtomicType val = 0; 159 memset(&val, 0xa5, sizeof(AtomicType)); 160 return val; 161 } 162 163 // This is a simple sanity check that values are correct. Not testing 164 // atomicity 165 template <class AtomicType> 166 static void TestStore() { 167 const AtomicType kVal1 = TestFillValue<AtomicType>(); 168 const AtomicType kVal2 = static_cast<AtomicType>(-1); 169 170 AtomicType value; 171 172 base::subtle::NoBarrier_Store(&value, kVal1); 173 EXPECT_EQ(kVal1, value); 174 base::subtle::NoBarrier_Store(&value, kVal2); 175 EXPECT_EQ(kVal2, value); 176 177 base::subtle::Acquire_Store(&value, kVal1); 178 EXPECT_EQ(kVal1, value); 179 base::subtle::Acquire_Store(&value, kVal2); 180 EXPECT_EQ(kVal2, value); 181 182 base::subtle::Release_Store(&value, kVal1); 183 EXPECT_EQ(kVal1, value); 184 base::subtle::Release_Store(&value, kVal2); 185 EXPECT_EQ(kVal2, value); 186 } 187 188 // This is a simple sanity check that values are correct. Not testing 189 // atomicity 190 template <class AtomicType> 191 static void TestLoad() { 192 const AtomicType kVal1 = TestFillValue<AtomicType>(); 193 const AtomicType kVal2 = static_cast<AtomicType>(-1); 194 195 AtomicType value; 196 197 value = kVal1; 198 EXPECT_EQ(kVal1, base::subtle::NoBarrier_Load(&value)); 199 value = kVal2; 200 EXPECT_EQ(kVal2, base::subtle::NoBarrier_Load(&value)); 201 202 value = kVal1; 203 EXPECT_EQ(kVal1, base::subtle::Acquire_Load(&value)); 204 value = kVal2; 205 EXPECT_EQ(kVal2, base::subtle::Acquire_Load(&value)); 206 207 value = kVal1; 208 EXPECT_EQ(kVal1, base::subtle::Release_Load(&value)); 209 value = kVal2; 210 EXPECT_EQ(kVal2, base::subtle::Release_Load(&value)); 211 } 212 213 TEST(AtomicOpsTest, Inc) { 214 TestAtomicIncrement<base::subtle::Atomic32>(); 215 TestAtomicIncrement<base::subtle::AtomicWord>(); 216 } 217 218 TEST(AtomicOpsTest, CompareAndSwap) { 219 TestCompareAndSwap<base::subtle::Atomic32>(); 220 TestCompareAndSwap<base::subtle::AtomicWord>(); 221 } 222 223 TEST(AtomicOpsTest, Exchange) { 224 TestAtomicExchange<base::subtle::Atomic32>(); 225 TestAtomicExchange<base::subtle::AtomicWord>(); 226 } 227 228 TEST(AtomicOpsTest, IncrementBounds) { 229 TestAtomicIncrementBounds<base::subtle::Atomic32>(); 230 TestAtomicIncrementBounds<base::subtle::AtomicWord>(); 231 } 232 233 TEST(AtomicOpsTest, Store) { 234 TestStore<base::subtle::Atomic32>(); 235 TestStore<base::subtle::AtomicWord>(); 236 } 237 238 TEST(AtomicOpsTest, Load) { 239 TestLoad<base::subtle::Atomic32>(); 240 TestLoad<base::subtle::AtomicWord>(); 241 } 242