| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
| /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
| /* This Source Code Form is subject to the terms of the Mozilla Public |
| * License, v. 2.0. If a copy of the MPL was not distributed with this |
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| |
| #include "mozilla/Assertions.h" |
| #include "mozilla/Atomics.h" |
| |
| #include <stdint.h> |
| |
| using mozilla::Atomic; |
| using mozilla::MemoryOrdering; |
| using mozilla::Relaxed; |
| using mozilla::ReleaseAcquire; |
| using mozilla::SequentiallyConsistent; |
| |
| #define A(a,b) MOZ_RELEASE_ASSERT(a,b) |
| |
| template <typename T, MemoryOrdering Order> |
| static void |
| TestTypeWithOrdering() |
| { |
| Atomic<T, Order> atomic(5); |
| A(atomic == 5, "Atomic variable did not initialize"); |
| |
| // Test atomic increment |
| A(++atomic == T(6), "Atomic increment did not work"); |
| A(atomic++ == T(6), "Atomic post-increment did not work"); |
| A(atomic == T(7), "Atomic post-increment did not work"); |
| |
| // Test atomic decrement |
| A(--atomic == 6, "Atomic decrement did not work"); |
| A(atomic-- == 6, "Atomic post-decrement did not work"); |
| A(atomic == 5, "Atomic post-decrement did not work"); |
| |
| // Test other arithmetic. |
| T result; |
| result = (atomic += T(5)); |
| A(atomic == T(10), "Atomic += did not work"); |
| A(result == T(10), "Atomic += returned the wrong value"); |
| result = (atomic -= T(3)); |
| A(atomic == T(7), "Atomic -= did not work"); |
| A(result == T(7), "Atomic -= returned the wrong value"); |
| |
| // Test assignment |
| result = (atomic = T(5)); |
| A(atomic == T(5), "Atomic assignment failed"); |
| A(result == T(5), "Atomic assignment returned the wrong value"); |
| |
| // Test logical operations. |
| result = (atomic ^= T(2)); |
| A(atomic == T(7), "Atomic ^= did not work"); |
| A(result == T(7), "Atomic ^= returned the wrong value"); |
| result = (atomic ^= T(4)); |
| A(atomic == T(3), "Atomic ^= did not work"); |
| A(result == T(3), "Atomic ^= returned the wrong value"); |
| result = (atomic |= T(8)); |
| A(atomic == T(11), "Atomic |= did not work"); |
| A(result == T(11), "Atomic |= returned the wrong value"); |
| result = (atomic |= T(8)); |
| A(atomic == T(11), "Atomic |= did not work"); |
| A(result == T(11), "Atomic |= returned the wrong value"); |
| result = (atomic &= T(12)); |
| A(atomic == T(8), "Atomic &= did not work"); |
| A(result == T(8), "Atomic &= returned the wrong value"); |
| |
| // Test exchange. |
| atomic = T(30); |
| result = atomic.exchange(42); |
| A(atomic == T(42), "Atomic exchange did not work"); |
| A(result == T(30), "Atomic exchange returned the wrong value"); |
| |
| // Test CAS. |
| atomic = T(1); |
| bool boolResult = atomic.compareExchange(0, 2); |
| A(!boolResult, "CAS should have returned false."); |
| A(atomic == T(1), "CAS shouldn't have done anything."); |
| |
| boolResult = atomic.compareExchange(1, 42); |
| A(boolResult, "CAS should have succeeded."); |
| A(atomic == T(42), "CAS should have changed atomic's value."); |
| } |
| |
| template<typename T, MemoryOrdering Order> |
| static void |
| TestPointerWithOrdering() |
| { |
| T array1[10]; |
| Atomic<T*, Order> atomic(array1); |
| A(atomic == array1, "Atomic variable did not initialize"); |
| |
| // Test atomic increment |
| A(++atomic == array1 + 1, "Atomic increment did not work"); |
| A(atomic++ == array1 + 1, "Atomic post-increment did not work"); |
| A(atomic == array1 + 2, "Atomic post-increment did not work"); |
| |
| // Test atomic decrement |
| A(--atomic == array1 + 1, "Atomic decrement did not work"); |
| A(atomic-- == array1 + 1, "Atomic post-decrement did not work"); |
| A(atomic == array1, "Atomic post-decrement did not work"); |
| |
| // Test other arithmetic operations |
| T* result; |
| result = (atomic += 2); |
| A(atomic == array1 + 2, "Atomic += did not work"); |
| A(result == array1 + 2, "Atomic += returned the wrong value"); |
| result = (atomic -= 1); |
| A(atomic == array1 + 1, "Atomic -= did not work"); |
| A(result == array1 + 1, "Atomic -= returned the wrong value"); |
| |
| // Test stores |
| result = (atomic = array1); |
| A(atomic == array1, "Atomic assignment did not work"); |
| A(result == array1, "Atomic assignment returned the wrong value"); |
| |
| // Test exchange |
| atomic = array1 + 2; |
| result = atomic.exchange(array1); |
| A(atomic == array1, "Atomic exchange did not work"); |
| A(result == array1 + 2, "Atomic exchange returned the wrong value"); |
| |
| atomic = array1; |
| bool boolResult = atomic.compareExchange(array1 + 1, array1 + 2); |
| A(!boolResult, "CAS should have returned false."); |
| A(atomic == array1, "CAS shouldn't have done anything."); |
| |
| boolResult = atomic.compareExchange(array1, array1 + 3); |
| A(boolResult, "CAS should have succeeded."); |
| A(atomic == array1 + 3, "CAS should have changed atomic's value."); |
| } |
| |
| enum EnumType |
| { |
| EnumType_0 = 0, |
| EnumType_1 = 1, |
| EnumType_2 = 2, |
| EnumType_3 = 3 |
| }; |
| |
| template<MemoryOrdering Order> |
| static void |
| TestEnumWithOrdering() |
| { |
| Atomic<EnumType, Order> atomic(EnumType_2); |
| A(atomic == EnumType_2, "Atomic variable did not initialize"); |
| |
| // Test assignment |
| EnumType result; |
| result = (atomic = EnumType_3); |
| A(atomic == EnumType_3, "Atomic assignment failed"); |
| A(result == EnumType_3, "Atomic assignment returned the wrong value"); |
| |
| // Test exchange. |
| atomic = EnumType_1; |
| result = atomic.exchange(EnumType_2); |
| A(atomic == EnumType_2, "Atomic exchange did not work"); |
| A(result == EnumType_1, "Atomic exchange returned the wrong value"); |
| |
| // Test CAS. |
| atomic = EnumType_1; |
| bool boolResult = atomic.compareExchange(EnumType_0, EnumType_2); |
| A(!boolResult, "CAS should have returned false."); |
| A(atomic == EnumType_1, "CAS shouldn't have done anything."); |
| |
| boolResult = atomic.compareExchange(EnumType_1, EnumType_3); |
| A(boolResult, "CAS should have succeeded."); |
| A(atomic == EnumType_3, "CAS should have changed atomic's value."); |
| } |
| |
| enum class EnumClass : uint32_t |
| { |
| Value0 = 0, |
| Value1 = 1, |
| Value2 = 2, |
| Value3 = 3 |
| }; |
| |
| template<MemoryOrdering Order> |
| static void |
| TestEnumClassWithOrdering() |
| { |
| Atomic<EnumClass, Order> atomic(EnumClass::Value2); |
| A(atomic == EnumClass::Value2, "Atomic variable did not initialize"); |
| |
| // Test assignment |
| EnumClass result; |
| result = (atomic = EnumClass::Value3); |
| A(atomic == EnumClass::Value3, "Atomic assignment failed"); |
| A(result == EnumClass::Value3, "Atomic assignment returned the wrong value"); |
| |
| // Test exchange. |
| atomic = EnumClass::Value1; |
| result = atomic.exchange(EnumClass::Value2); |
| A(atomic == EnumClass::Value2, "Atomic exchange did not work"); |
| A(result == EnumClass::Value1, "Atomic exchange returned the wrong value"); |
| |
| // Test CAS. |
| atomic = EnumClass::Value1; |
| bool boolResult = atomic.compareExchange(EnumClass::Value0, EnumClass::Value2); |
| A(!boolResult, "CAS should have returned false."); |
| A(atomic == EnumClass::Value1, "CAS shouldn't have done anything."); |
| |
| boolResult = atomic.compareExchange(EnumClass::Value1, EnumClass::Value3); |
| A(boolResult, "CAS should have succeeded."); |
| A(atomic == EnumClass::Value3, "CAS should have changed atomic's value."); |
| } |
| |
| template <MemoryOrdering Order> |
| static void |
| TestBoolWithOrdering() |
| { |
| Atomic<bool, Order> atomic(false); |
| A(atomic == false, "Atomic variable did not initialize"); |
| |
| // Test assignment |
| bool result; |
| result = (atomic = true); |
| A(atomic == true, "Atomic assignment failed"); |
| A(result == true, "Atomic assignment returned the wrong value"); |
| |
| // Test exchange. |
| atomic = false; |
| result = atomic.exchange(true); |
| A(atomic == true, "Atomic exchange did not work"); |
| A(result == false, "Atomic exchange returned the wrong value"); |
| |
| // Test CAS. |
| atomic = false; |
| bool boolResult = atomic.compareExchange(true, false); |
| A(!boolResult, "CAS should have returned false."); |
| A(atomic == false, "CAS shouldn't have done anything."); |
| |
| boolResult = atomic.compareExchange(false, true); |
| A(boolResult, "CAS should have succeeded."); |
| A(atomic == true, "CAS should have changed atomic's value."); |
| } |
| |
| template <typename T> |
| static void |
| TestType() |
| { |
| TestTypeWithOrdering<T, SequentiallyConsistent>(); |
| TestTypeWithOrdering<T, ReleaseAcquire>(); |
| TestTypeWithOrdering<T, Relaxed>(); |
| } |
| |
| template<typename T> |
| static void |
| TestPointer() |
| { |
| TestPointerWithOrdering<T, SequentiallyConsistent>(); |
| TestPointerWithOrdering<T, ReleaseAcquire>(); |
| TestPointerWithOrdering<T, Relaxed>(); |
| } |
| |
| static void |
| TestEnum() |
| { |
| TestEnumWithOrdering<SequentiallyConsistent>(); |
| TestEnumWithOrdering<ReleaseAcquire>(); |
| TestEnumWithOrdering<Relaxed>(); |
| |
| TestEnumClassWithOrdering<SequentiallyConsistent>(); |
| TestEnumClassWithOrdering<ReleaseAcquire>(); |
| TestEnumClassWithOrdering<Relaxed>(); |
| } |
| |
| static void |
| TestBool() |
| { |
| TestBoolWithOrdering<SequentiallyConsistent>(); |
| TestBoolWithOrdering<ReleaseAcquire>(); |
| TestBoolWithOrdering<Relaxed>(); |
| } |
| |
| #undef A |
| |
| int |
| main() |
| { |
| TestType<uint32_t>(); |
| TestType<int32_t>(); |
| TestType<uint64_t>(); |
| TestType<int64_t>(); |
| TestType<intptr_t>(); |
| TestType<uintptr_t>(); |
| TestPointer<int>(); |
| TestPointer<float>(); |
| TestPointer<uint16_t*>(); |
| TestPointer<uint32_t*>(); |
| TestEnum(); |
| TestBool(); |
| return 0; |
| } |