1f25ce65dSSergey Makeev // The MIT License (MIT) 2f25ce65dSSergey Makeev // 3f25ce65dSSergey Makeev // Copyright (c) 2015 Sergey Makeev, Vadim Slyusarev 4f25ce65dSSergey Makeev // 5f25ce65dSSergey Makeev // Permission is hereby granted, free of charge, to any person obtaining a copy 6f25ce65dSSergey Makeev // of this software and associated documentation files (the "Software"), to deal 7f25ce65dSSergey Makeev // in the Software without restriction, including without limitation the rights 8f25ce65dSSergey Makeev // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9f25ce65dSSergey Makeev // copies of the Software, and to permit persons to whom the Software is 10f25ce65dSSergey Makeev // furnished to do so, subject to the following conditions: 11f25ce65dSSergey Makeev // 12f25ce65dSSergey Makeev // The above copyright notice and this permission notice shall be included in 13f25ce65dSSergey Makeev // all copies or substantial portions of the Software. 14f25ce65dSSergey Makeev // 15f25ce65dSSergey Makeev // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16f25ce65dSSergey Makeev // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17f25ce65dSSergey Makeev // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18f25ce65dSSergey Makeev // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19f25ce65dSSergey Makeev // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20f25ce65dSSergey Makeev // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21f25ce65dSSergey Makeev // THE SOFTWARE. 22f25ce65dSSergey Makeev 2347d53e4dSSergey Makeev #pragma once 2447d53e4dSSergey Makeev 2581ec7369SSergey Makeev #ifndef __MT_ATOMIC__ 2681ec7369SSergey Makeev #define __MT_ATOMIC__ 2781ec7369SSergey Makeev 281e78cb24Ss.makeev_local #include <MTConfig.h> 2981ec7369SSergey Makeev #include <intrin.h> 3081ec7369SSergey Makeev #include <cstdint> 31498f3d32SSergey Makeev #include <type_traits> 322e846c40SSergey Makeev #include <xmmintrin.h> 3381ec7369SSergey Makeev 34721f8c0bSs.makeev_local #define MT_ATOMIC_COMPILE_TIME_CHECK \ 35721f8c0bSs.makeev_local static_assert(std::is_pod< Atomic32Base<T> >::value == true, "Atomic32Base must be a POD (plain old data type)"); \ 36721f8c0bSs.makeev_local static_assert(sizeof(T) == sizeof(int32), "Atomic32Base, type T must be equal size as int32"); \ 37721f8c0bSs.makeev_local static_assert(sizeof(int32) == sizeof(long), "Incompatible types, Interlocked* will fail."); 38721f8c0bSs.makeev_local 39721f8c0bSs.makeev_local #define MT_ATOMICPTR_COMPILE_TIME_CHECK \ 40721f8c0bSs.makeev_local static_assert(std::is_pod< AtomicPtrBase<T> >::value == true, "AtomicPtrBase must be a POD (plain old data type)"); 41721f8c0bSs.makeev_local 42*d10ac48cSSergey Makeev #ifdef YieldProcessor 43*d10ac48cSSergey Makeev #undef YieldProcessor 44*d10ac48cSSergey Makeev #endif 45*d10ac48cSSergey Makeev 46721f8c0bSs.makeev_local 4747d53e4dSSergey Makeev namespace MT 4847d53e4dSSergey Makeev { 49498f3d32SSergey Makeev // 50498f3d32SSergey Makeev // Full memory barrier 51498f3d32SSergey Makeev // 52498f3d32SSergey Makeev //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// HardwareFullMemoryBarrier()5381ec7369SSergey Makeev inline void HardwareFullMemoryBarrier() 5481ec7369SSergey Makeev { 5581ec7369SSergey Makeev _mm_mfence(); 5681ec7369SSergey Makeev } 5781ec7369SSergey Makeev 5847d53e4dSSergey Makeev // 592e846c40SSergey Makeev // Signals to the processor to give resources to threads that are waiting for them. 602e846c40SSergey Makeev // 612e846c40SSergey Makeev //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// YieldProcessor()62*d10ac48cSSergey Makeev inline void YieldProcessor() 632e846c40SSergey Makeev { 642e846c40SSergey Makeev _mm_pause(); 652e846c40SSergey Makeev } 662e846c40SSergey Makeev 672e846c40SSergey Makeev 682e846c40SSergey Makeev // 69498f3d32SSergey Makeev // Atomic int (pod type) 70721f8c0bSs.makeev_local // The operation is ordered in a sequentially consistent manner except for functions marked as relaxed. 7147d53e4dSSergey Makeev // 72721f8c0bSs.makeev_local // Note: You must use this type when you need to declare static variable instead of Atomic32 73498f3d32SSergey Makeev // 74498f3d32SSergey Makeev //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 75721f8c0bSs.makeev_local template<typename T> 76721f8c0bSs.makeev_local struct Atomic32Base 7747d53e4dSSergey Makeev { 789c716f68Ss.makeev_local T _value; 7947d53e4dSSergey Makeev 8047d53e4dSSergey Makeev // The function returns the resulting added value. AddFetchAtomic32Base81721f8c0bSs.makeev_local T AddFetch(T sum) 82721f8c0bSs.makeev_local { MT_ATOMIC_COMPILE_TIME_CHECK 83721f8c0bSs.makeev_local 84721f8c0bSs.makeev_local mt_release_fence(); 85721f8c0bSs.makeev_local T tmp = _InterlockedExchangeAdd((volatile long*)&_value, sum) + sum; 86721f8c0bSs.makeev_local mt_acquire_fence(); 87721f8c0bSs.makeev_local return tmp; 8847d53e4dSSergey Makeev } 8947d53e4dSSergey Makeev 9047d53e4dSSergey Makeev // The function returns the resulting incremented value. IncFetchAtomic32Base91721f8c0bSs.makeev_local T IncFetch() 92721f8c0bSs.makeev_local { MT_ATOMIC_COMPILE_TIME_CHECK 93721f8c0bSs.makeev_local 94721f8c0bSs.makeev_local mt_release_fence(); 95721f8c0bSs.makeev_local T tmp = _InterlockedIncrement((volatile long*)&_value); 96721f8c0bSs.makeev_local mt_acquire_fence(); 97721f8c0bSs.makeev_local return tmp; 9847d53e4dSSergey Makeev } 9947d53e4dSSergey Makeev 10047d53e4dSSergey Makeev // The function returns the resulting decremented value. DecFetchAtomic32Base101721f8c0bSs.makeev_local T DecFetch() 102721f8c0bSs.makeev_local { MT_ATOMIC_COMPILE_TIME_CHECK 103721f8c0bSs.makeev_local 104721f8c0bSs.makeev_local mt_release_fence(); 105721f8c0bSs.makeev_local T tmp = _InterlockedDecrement((volatile long*)&_value); 106721f8c0bSs.makeev_local mt_acquire_fence(); 107721f8c0bSs.makeev_local return tmp; 10847d53e4dSSergey Makeev } 10947d53e4dSSergey Makeev LoadAtomic32Base110721f8c0bSs.makeev_local T Load() const 111721f8c0bSs.makeev_local { MT_ATOMIC_COMPILE_TIME_CHECK 112721f8c0bSs.makeev_local 113721f8c0bSs.makeev_local T tmp = LoadRelaxed(); 114721f8c0bSs.makeev_local mt_acquire_fence(); 115721f8c0bSs.makeev_local return tmp; 116721f8c0bSs.makeev_local } 117721f8c0bSs.makeev_local StoreAtomic32Base1185d2fe9cbSs.makeev_local void Store(T val) 119721f8c0bSs.makeev_local { MT_ATOMIC_COMPILE_TIME_CHECK 120721f8c0bSs.makeev_local 121721f8c0bSs.makeev_local mt_release_fence(); 122721f8c0bSs.makeev_local StoreRelaxed(val); 12347d53e4dSSergey Makeev } 12447d53e4dSSergey Makeev 12547d53e4dSSergey Makeev // The function returns the initial value. ExchangeAtomic32Base126721f8c0bSs.makeev_local T Exchange(T val) 127721f8c0bSs.makeev_local { MT_ATOMIC_COMPILE_TIME_CHECK 128721f8c0bSs.makeev_local 129721f8c0bSs.makeev_local mt_release_fence(); 130721f8c0bSs.makeev_local T tmp = _InterlockedExchange((volatile long*)&_value, val); 131721f8c0bSs.makeev_local mt_acquire_fence(); 132721f8c0bSs.makeev_local return tmp; 13347d53e4dSSergey Makeev } 13446be836dSSergey Makeev 13546be836dSSergey Makeev // The function returns the initial value. CompareAndSwapAtomic32Base136721f8c0bSs.makeev_local T CompareAndSwap(T compareValue, T newValue) 137721f8c0bSs.makeev_local { MT_ATOMIC_COMPILE_TIME_CHECK 138721f8c0bSs.makeev_local 139721f8c0bSs.makeev_local mt_release_fence(); 140721f8c0bSs.makeev_local T tmp = _InterlockedCompareExchange((volatile long*)&_value, newValue, compareValue); 141721f8c0bSs.makeev_local mt_acquire_fence(); 142721f8c0bSs.makeev_local return tmp; 14346be836dSSergey Makeev } 14481ec7369SSergey Makeev 14581ec7369SSergey Makeev // Relaxed operation: there are no synchronization or ordering constraints LoadRelaxedAtomic32Base146721f8c0bSs.makeev_local T LoadRelaxed() const 147721f8c0bSs.makeev_local { MT_ATOMIC_COMPILE_TIME_CHECK 148721f8c0bSs.makeev_local 149498f3d32SSergey Makeev return _value; 15081ec7369SSergey Makeev } 15181ec7369SSergey Makeev 15281ec7369SSergey Makeev // Relaxed operation: there are no synchronization or ordering constraints StoreRelaxedAtomic32Base1535d2fe9cbSs.makeev_local void StoreRelaxed(T val) 154721f8c0bSs.makeev_local { MT_ATOMIC_COMPILE_TIME_CHECK 155721f8c0bSs.makeev_local 156498f3d32SSergey Makeev _value = val; 15781ec7369SSergey Makeev } 15881ec7369SSergey Makeev 15947d53e4dSSergey Makeev }; 16047d53e4dSSergey Makeev 161efd3d0d5SSergey Makeev 1628dd496e0SSergey Makeev 1638dd496e0SSergey Makeev 164498f3d32SSergey Makeev 165efd3d0d5SSergey Makeev // 166498f3d32SSergey Makeev // Atomic pointer (pod type) 167efd3d0d5SSergey Makeev // 1682f083884Ss.makeev_local // You must use this type when you need to declare static variable instead of AtomicPtr 169498f3d32SSergey Makeev // 170498f3d32SSergey Makeev //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 171721f8c0bSs.makeev_local template<typename T> 172498f3d32SSergey Makeev struct AtomicPtrBase 173efd3d0d5SSergey Makeev { 1749c716f68Ss.makeev_local T* _value; 175efd3d0d5SSergey Makeev LoadAtomicPtrBase176721f8c0bSs.makeev_local T* Load() const 177721f8c0bSs.makeev_local { MT_ATOMICPTR_COMPILE_TIME_CHECK 178721f8c0bSs.makeev_local 179721f8c0bSs.makeev_local T* tmp = LoadRelaxed(); 180721f8c0bSs.makeev_local mt_acquire_fence(); 181721f8c0bSs.makeev_local return tmp; 182721f8c0bSs.makeev_local } 183721f8c0bSs.makeev_local StoreAtomicPtrBase184721f8c0bSs.makeev_local void Store(const T* val) 185721f8c0bSs.makeev_local { MT_ATOMICPTR_COMPILE_TIME_CHECK 186721f8c0bSs.makeev_local 187721f8c0bSs.makeev_local mt_release_fence(); 188721f8c0bSs.makeev_local StoreRelaxed(val); 189efd3d0d5SSergey Makeev } 190efd3d0d5SSergey Makeev 191efd3d0d5SSergey Makeev // The function returns the initial value. ExchangeAtomicPtrBase192721f8c0bSs.makeev_local T* Exchange(const T* val) 193721f8c0bSs.makeev_local { MT_ATOMICPTR_COMPILE_TIME_CHECK 194721f8c0bSs.makeev_local 195721f8c0bSs.makeev_local mt_release_fence(); 1961e78cb24Ss.makeev_local #ifndef MT_PTR64 197ed6f50edSSergey Makeev static_assert(sizeof(long) == sizeof(void*), "Incompatible types, _InterlockedExchange will fail"); 198721f8c0bSs.makeev_local T* tmp = (T*)_InterlockedExchange((volatile long*)&_value, (long)val); 19981ec7369SSergey Makeev #else 200721f8c0bSs.makeev_local T* tmp = (T*)_InterlockedExchangePointer((void* volatile*)&_value, (void*)val); 20181ec7369SSergey Makeev #endif 202721f8c0bSs.makeev_local mt_acquire_fence(); 203721f8c0bSs.makeev_local return tmp; 204efd3d0d5SSergey Makeev } 205efd3d0d5SSergey Makeev 206efd3d0d5SSergey Makeev // The function returns the initial value. CompareAndSwapAtomicPtrBase207721f8c0bSs.makeev_local T* CompareAndSwap(const T* compareValue, const T* newValue) 208721f8c0bSs.makeev_local { MT_ATOMICPTR_COMPILE_TIME_CHECK 209721f8c0bSs.makeev_local 210721f8c0bSs.makeev_local mt_release_fence(); 2111e78cb24Ss.makeev_local #ifndef MT_PTR64 212ed6f50edSSergey Makeev static_assert(sizeof(long) == sizeof(void*), "Incompatible types, _InterlockedCompareExchange will fail"); 213721f8c0bSs.makeev_local T* tmp = (T*)_InterlockedCompareExchange((volatile long*)&_value, (long)newValue, (long)compareValue); 21481ec7369SSergey Makeev #else 215721f8c0bSs.makeev_local T* tmp = (T*)_InterlockedCompareExchangePointer((void* volatile*)&_value, (void*)newValue, (void*)compareValue); 21681ec7369SSergey Makeev #endif 217721f8c0bSs.makeev_local mt_acquire_fence(); 218721f8c0bSs.makeev_local return tmp; 219efd3d0d5SSergey Makeev } 22081ec7369SSergey Makeev 22181ec7369SSergey Makeev // Relaxed operation: there are no synchronization or ordering constraints LoadRelaxedAtomicPtrBase222721f8c0bSs.makeev_local T* LoadRelaxed() const 223721f8c0bSs.makeev_local { MT_ATOMICPTR_COMPILE_TIME_CHECK 224721f8c0bSs.makeev_local 225721f8c0bSs.makeev_local return _value; 22681ec7369SSergey Makeev } 22781ec7369SSergey Makeev 22881ec7369SSergey Makeev // Relaxed operation: there are no synchronization or ordering constraints StoreRelaxedAtomicPtrBase229721f8c0bSs.makeev_local void StoreRelaxed(const T* val) 230721f8c0bSs.makeev_local { MT_ATOMICPTR_COMPILE_TIME_CHECK 231721f8c0bSs.makeev_local 232721f8c0bSs.makeev_local _value = (T*)val; 23381ec7369SSergey Makeev } 23481ec7369SSergey Makeev 235efd3d0d5SSergey Makeev }; 236efd3d0d5SSergey Makeev 237efd3d0d5SSergey Makeev 238498f3d32SSergey Makeev 23947d53e4dSSergey Makeev } 24081ec7369SSergey Makeev 24181ec7369SSergey Makeev 242721f8c0bSs.makeev_local #undef MT_ATOMIC_COMPILE_TIME_CHECK 243721f8c0bSs.makeev_local 244721f8c0bSs.makeev_local 24581ec7369SSergey Makeev #endif 246