Home | History | Annotate | Download | only in base
      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