| // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include "base/atomicops.h" | 
 |  | 
 | #include <stdint.h> | 
 | #include <string.h> | 
 |  | 
 | #include "testing/gtest/include/gtest/gtest.h" | 
 |  | 
 | template <class AtomicType> | 
 | static void TestAtomicIncrement() { | 
 |   // For now, we just test single threaded execution | 
 |  | 
 |   // use a guard value to make sure the NoBarrier_AtomicIncrement doesn't go | 
 |   // outside the expected address bounds.  This is in particular to | 
 |   // test that some future change to the asm code doesn't cause the | 
 |   // 32-bit NoBarrier_AtomicIncrement doesn't do the wrong thing on 64-bit | 
 |   // machines. | 
 |   struct { | 
 |     AtomicType prev_word; | 
 |     AtomicType count; | 
 |     AtomicType next_word; | 
 |   } s; | 
 |  | 
 |   AtomicType prev_word_value, next_word_value; | 
 |   memset(&prev_word_value, 0xFF, sizeof(AtomicType)); | 
 |   memset(&next_word_value, 0xEE, sizeof(AtomicType)); | 
 |  | 
 |   s.prev_word = prev_word_value; | 
 |   s.count = 0; | 
 |   s.next_word = next_word_value; | 
 |  | 
 |   EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 1), 1); | 
 |   EXPECT_EQ(s.count, 1); | 
 |   EXPECT_EQ(s.prev_word, prev_word_value); | 
 |   EXPECT_EQ(s.next_word, next_word_value); | 
 |  | 
 |   EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 2), 3); | 
 |   EXPECT_EQ(s.count, 3); | 
 |   EXPECT_EQ(s.prev_word, prev_word_value); | 
 |   EXPECT_EQ(s.next_word, next_word_value); | 
 |  | 
 |   EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 3), 6); | 
 |   EXPECT_EQ(s.count, 6); | 
 |   EXPECT_EQ(s.prev_word, prev_word_value); | 
 |   EXPECT_EQ(s.next_word, next_word_value); | 
 |  | 
 |   EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -3), 3); | 
 |   EXPECT_EQ(s.count, 3); | 
 |   EXPECT_EQ(s.prev_word, prev_word_value); | 
 |   EXPECT_EQ(s.next_word, next_word_value); | 
 |  | 
 |   EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -2), 1); | 
 |   EXPECT_EQ(s.count, 1); | 
 |   EXPECT_EQ(s.prev_word, prev_word_value); | 
 |   EXPECT_EQ(s.next_word, next_word_value); | 
 |  | 
 |   EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -1), 0); | 
 |   EXPECT_EQ(s.count, 0); | 
 |   EXPECT_EQ(s.prev_word, prev_word_value); | 
 |   EXPECT_EQ(s.next_word, next_word_value); | 
 |  | 
 |   EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -1), -1); | 
 |   EXPECT_EQ(s.count, -1); | 
 |   EXPECT_EQ(s.prev_word, prev_word_value); | 
 |   EXPECT_EQ(s.next_word, next_word_value); | 
 |  | 
 |   EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -4), -5); | 
 |   EXPECT_EQ(s.count, -5); | 
 |   EXPECT_EQ(s.prev_word, prev_word_value); | 
 |   EXPECT_EQ(s.next_word, next_word_value); | 
 |  | 
 |   EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 5), 0); | 
 |   EXPECT_EQ(s.count, 0); | 
 |   EXPECT_EQ(s.prev_word, prev_word_value); | 
 |   EXPECT_EQ(s.next_word, next_word_value); | 
 | } | 
 |  | 
 |  | 
 | #define NUM_BITS(T) (sizeof(T) * 8) | 
 |  | 
 |  | 
 | template <class AtomicType> | 
 | static void TestCompareAndSwap() { | 
 |   AtomicType value = 0; | 
 |   AtomicType prev = base::subtle::NoBarrier_CompareAndSwap(&value, 0, 1); | 
 |   EXPECT_EQ(1, value); | 
 |   EXPECT_EQ(0, prev); | 
 |  | 
 |   // Use test value that has non-zero bits in both halves, more for testing | 
 |   // 64-bit implementation on 32-bit platforms. | 
 |   const AtomicType k_test_val = (static_cast<uint64_t>(1) << | 
 |                                  (NUM_BITS(AtomicType) - 2)) + 11; | 
 |   value = k_test_val; | 
 |   prev = base::subtle::NoBarrier_CompareAndSwap(&value, 0, 5); | 
 |   EXPECT_EQ(k_test_val, value); | 
 |   EXPECT_EQ(k_test_val, prev); | 
 |  | 
 |   value = k_test_val; | 
 |   prev = base::subtle::NoBarrier_CompareAndSwap(&value, k_test_val, 5); | 
 |   EXPECT_EQ(5, value); | 
 |   EXPECT_EQ(k_test_val, prev); | 
 | } | 
 |  | 
 |  | 
 | template <class AtomicType> | 
 | static void TestAtomicExchange() { | 
 |   AtomicType value = 0; | 
 |   AtomicType new_value = base::subtle::NoBarrier_AtomicExchange(&value, 1); | 
 |   EXPECT_EQ(1, value); | 
 |   EXPECT_EQ(0, new_value); | 
 |  | 
 |   // Use test value that has non-zero bits in both halves, more for testing | 
 |   // 64-bit implementation on 32-bit platforms. | 
 |   const AtomicType k_test_val = (static_cast<uint64_t>(1) << | 
 |                                  (NUM_BITS(AtomicType) - 2)) + 11; | 
 |   value = k_test_val; | 
 |   new_value = base::subtle::NoBarrier_AtomicExchange(&value, k_test_val); | 
 |   EXPECT_EQ(k_test_val, value); | 
 |   EXPECT_EQ(k_test_val, new_value); | 
 |  | 
 |   value = k_test_val; | 
 |   new_value = base::subtle::NoBarrier_AtomicExchange(&value, 5); | 
 |   EXPECT_EQ(5, value); | 
 |   EXPECT_EQ(k_test_val, new_value); | 
 | } | 
 |  | 
 |  | 
 | template <class AtomicType> | 
 | static void TestAtomicIncrementBounds() { | 
 |   // Test at rollover boundary between int_max and int_min | 
 |   AtomicType test_val = (static_cast<uint64_t>(1) << | 
 |                          (NUM_BITS(AtomicType) - 1)); | 
 |   AtomicType value = -1 ^ test_val; | 
 |   AtomicType new_value = base::subtle::NoBarrier_AtomicIncrement(&value, 1); | 
 |   EXPECT_EQ(test_val, value); | 
 |   EXPECT_EQ(value, new_value); | 
 |  | 
 |   base::subtle::NoBarrier_AtomicIncrement(&value, -1); | 
 |   EXPECT_EQ(-1 ^ test_val, value); | 
 |  | 
 |   // Test at 32-bit boundary for 64-bit atomic type. | 
 |   test_val = static_cast<uint64_t>(1) << (NUM_BITS(AtomicType) / 2); | 
 |   value = test_val - 1; | 
 |   new_value = base::subtle::NoBarrier_AtomicIncrement(&value, 1); | 
 |   EXPECT_EQ(test_val, value); | 
 |   EXPECT_EQ(value, new_value); | 
 |  | 
 |   base::subtle::NoBarrier_AtomicIncrement(&value, -1); | 
 |   EXPECT_EQ(test_val - 1, value); | 
 | } | 
 |  | 
 | // Return an AtomicType with the value 0xa5a5a5.. | 
 | template <class AtomicType> | 
 | static AtomicType TestFillValue() { | 
 |   AtomicType val = 0; | 
 |   memset(&val, 0xa5, sizeof(AtomicType)); | 
 |   return val; | 
 | } | 
 |  | 
 | // This is a simple sanity check that values are correct. Not testing | 
 | // atomicity | 
 | template <class AtomicType> | 
 | static void TestStore() { | 
 |   const AtomicType kVal1 = TestFillValue<AtomicType>(); | 
 |   const AtomicType kVal2 = static_cast<AtomicType>(-1); | 
 |  | 
 |   AtomicType value; | 
 |  | 
 |   base::subtle::NoBarrier_Store(&value, kVal1); | 
 |   EXPECT_EQ(kVal1, value); | 
 |   base::subtle::NoBarrier_Store(&value, kVal2); | 
 |   EXPECT_EQ(kVal2, value); | 
 |  | 
 |   base::subtle::Acquire_Store(&value, kVal1); | 
 |   EXPECT_EQ(kVal1, value); | 
 |   base::subtle::Acquire_Store(&value, kVal2); | 
 |   EXPECT_EQ(kVal2, value); | 
 |  | 
 |   base::subtle::Release_Store(&value, kVal1); | 
 |   EXPECT_EQ(kVal1, value); | 
 |   base::subtle::Release_Store(&value, kVal2); | 
 |   EXPECT_EQ(kVal2, value); | 
 | } | 
 |  | 
 | // This is a simple sanity check that values are correct. Not testing | 
 | // atomicity | 
 | template <class AtomicType> | 
 | static void TestLoad() { | 
 |   const AtomicType kVal1 = TestFillValue<AtomicType>(); | 
 |   const AtomicType kVal2 = static_cast<AtomicType>(-1); | 
 |  | 
 |   AtomicType value; | 
 |  | 
 |   value = kVal1; | 
 |   EXPECT_EQ(kVal1, base::subtle::NoBarrier_Load(&value)); | 
 |   value = kVal2; | 
 |   EXPECT_EQ(kVal2, base::subtle::NoBarrier_Load(&value)); | 
 |  | 
 |   value = kVal1; | 
 |   EXPECT_EQ(kVal1, base::subtle::Acquire_Load(&value)); | 
 |   value = kVal2; | 
 |   EXPECT_EQ(kVal2, base::subtle::Acquire_Load(&value)); | 
 |  | 
 |   value = kVal1; | 
 |   EXPECT_EQ(kVal1, base::subtle::Release_Load(&value)); | 
 |   value = kVal2; | 
 |   EXPECT_EQ(kVal2, base::subtle::Release_Load(&value)); | 
 | } | 
 |  | 
 | TEST(AtomicOpsTest, Inc) { | 
 |   TestAtomicIncrement<base::subtle::Atomic32>(); | 
 |   TestAtomicIncrement<base::subtle::AtomicWord>(); | 
 | } | 
 |  | 
 | TEST(AtomicOpsTest, CompareAndSwap) { | 
 |   TestCompareAndSwap<base::subtle::Atomic32>(); | 
 |   TestCompareAndSwap<base::subtle::AtomicWord>(); | 
 | } | 
 |  | 
 | TEST(AtomicOpsTest, Exchange) { | 
 |   TestAtomicExchange<base::subtle::Atomic32>(); | 
 |   TestAtomicExchange<base::subtle::AtomicWord>(); | 
 | } | 
 |  | 
 | TEST(AtomicOpsTest, IncrementBounds) { | 
 |   TestAtomicIncrementBounds<base::subtle::Atomic32>(); | 
 |   TestAtomicIncrementBounds<base::subtle::AtomicWord>(); | 
 | } | 
 |  | 
 | TEST(AtomicOpsTest, Store) { | 
 |   TestStore<base::subtle::Atomic32>(); | 
 |   TestStore<base::subtle::AtomicWord>(); | 
 | } | 
 |  | 
 | TEST(AtomicOpsTest, Load) { | 
 |   TestLoad<base::subtle::Atomic32>(); | 
 |   TestLoad<base::subtle::AtomicWord>(); | 
 | } |