forked from mirrors/gecko-dev
		
	 4babb2b5ab
			
		
	
	
		4babb2b5ab
		
	
	
	
	
		
			
			Patch by bhackett and jlaster. Also reviewed by mccr8. Differential Revision: https://phabricator.services.mozilla.com/D60197 --HG-- extra : moz-landing-system : lando
		
			
				
	
	
		
			274 lines
		
	
	
	
		
			8.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			274 lines
		
	
	
	
		
			8.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- 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;
 | |
| }
 |