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