/** ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** * Copyright 2014 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ #ifndef POLY_ATOMIC_H_ #define POLY_ATOMIC_H_ #include #include #include #if XE_LIKE_OSX #include #endif // XE_LIKE_OSX namespace poly { // These functions are modeled off of the Apple OSAtomic routines // http://developer.apple.com/library/mac/#documentation/DriversKernelHardware/Reference/libkern_ref/OSAtomic_h/ #if XE_LIKE_OSX inline int32_t atomic_inc(volatile int32_t* value) { return OSAtomicIncrement32Barrier(reinterpret_cast(value)); } inline int32_t atomic_dec(volatile int32_t* value) { return OSAtomicDecrement32Barrier(reinterpret_cast(value)); } inline int32_t atomic_exchange(int32_t new_value, volatile int32_t* value) { return OSAtomicCompareAndSwap32Barrier(*value, new_value, value); } inline int64_t atomic_exchange(int64_t new_value, volatile int64_t* value) { return OSAtomicCompareAndSwap64Barrier(*value, new_value, value); } inline int32_t atomic_cas(int32_t old_value, int32_t new_value, volatile int32_t* value) { return OSAtomicCompareAndSwap32Barrier( old_value, new_value, reinterpret_cast(value)); } #elif XE_LIKE_WIN32 inline int32_t atomic_inc(volatile int32_t* value) { return InterlockedIncrement(reinterpret_cast(value)); } inline int32_t atomic_dec(volatile int32_t* value) { return InterlockedDecrement(reinterpret_cast(value)); } inline int32_t atomic_exchange(int32_t new_value, volatile int32_t* value) { return InterlockedExchange(reinterpret_cast(value), new_value); } inline int64_t atomic_exchange(int64_t new_value, volatile int64_t* value) { return InterlockedExchange64(reinterpret_cast(value), new_value); } inline int32_t atomic_cas(int32_t old_value, int32_t new_value, volatile int32_t* value) { return InterlockedCompareExchange(reinterpret_cast(value), new_value, old_value) == old_value; } #elif XE_LIKE_POSIX inline int32_t atomic_inc(volatile int32_t* value) { return __sync_add_and_fetch(value, 1); } inline int32_t atomic_dec(volatile int32_t* value) { return __sync_sub_and_fetch(value, 1); } inline int32_t atomic_exchange(int32_t new_value, volatile int32_t* value) { return __sync_val_compare_and_swap(*value, value, new_value); } inline int64_t atomic_exchange(int64_t new_value, volatile int64_t* value) { return __sync_val_compare_and_swap(*value, value, new_value); } inline int32_t atomic_cas(int32_t old_value, int32_t new_value, volatile int32_t* value) { return __sync_bool_compare_and_swap( reinterpret_cast(value), old_value, new_value); } #else #error No atomic primitives defined for this platform/cpu combination. #endif // OSX inline uint32_t atomic_inc(volatile uint32_t* value) { return static_cast( atomic_inc(reinterpret_cast(value))); } inline uint32_t atomic_dec(volatile uint32_t* value) { return static_cast( atomic_dec(reinterpret_cast(value))); } inline uint32_t atomic_exchange(uint32_t new_value, volatile uint32_t* value) { return static_cast( atomic_exchange(static_cast(new_value), reinterpret_cast(value))); } inline uint64_t atomic_exchange(uint64_t new_value, volatile uint64_t* value) { return static_cast( atomic_exchange(static_cast(new_value), reinterpret_cast(value))); } inline uint32_t atomic_cas(uint32_t old_value, uint32_t new_value, volatile uint32_t* value) { return static_cast(atomic_cas( static_cast(old_value), static_cast(new_value), reinterpret_cast(value))); } } // namespace poly #endif // POLY_ATOMIC_H_