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 <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