1 // The MIT License (MIT) 2 // 3 // Copyright (c) 2015 Sergey Makeev, Vadim Slyusarev 4 // 5 // Permission is hereby granted, free of charge, to any person obtaining a copy 6 // of this software and associated documentation files (the "Software"), to deal 7 // in the Software without restriction, including without limitation the rights 8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 // copies of the Software, and to permit persons to whom the Software is 10 // furnished to do so, subject to the following conditions: 11 // 12 // The above copyright notice and this permission notice shall be included in 13 // all copies or substantial portions of the Software. 14 // 15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 // THE SOFTWARE. 22 23 #pragma once 24 25 #ifndef __MT_ATOMIC__ 26 #define __MT_ATOMIC__ 27 28 #include <intrin.h> 29 #include <cstdint> 30 31 namespace MT 32 { 33 inline void HardwareFullMemoryBarrier() 34 { 35 _mm_mfence(); 36 } 37 38 // 39 // Atomic int 40 // 41 class AtomicInt32 42 { 43 volatile int32 value; 44 public: 45 46 AtomicInt32() 47 : value(0) 48 { 49 static_assert(sizeof(AtomicInt32) == 4, "Invalid type size"); 50 static_assert(sizeof(int32) == sizeof(long), "Incompatible types, Interlocked* will fail"); 51 MT_ASSERT(IsPointerAligned(&value, 4), "Invalid atomic int alignment"); 52 } 53 54 explicit AtomicInt32(int v) 55 : value(v) 56 { 57 static_assert(sizeof(AtomicInt32) == 4, "Invalid type size"); 58 static_assert(sizeof(int32) == sizeof(long), "Incompatible types, Interlocked* will fail"); 59 MT_ASSERT(IsPointerAligned(&value, 4), "Invalid atomic int alignment"); 60 } 61 62 // The function returns the resulting added value. 63 int32 AddFetch(int32 sum) 64 { 65 return _InterlockedExchangeAdd((volatile long *)&value, sum) + sum; 66 } 67 68 // The function returns the resulting incremented value. 69 int32 IncFetch() 70 { 71 return _InterlockedIncrement((volatile long *)&value); 72 } 73 74 // The function returns the resulting decremented value. 75 int32 DecFetch() 76 { 77 return _InterlockedDecrement((volatile long *)&value); 78 } 79 80 int32 Load() const 81 { 82 return value; 83 } 84 85 // The function returns the initial value. 86 int32 Store(int32 val) 87 { 88 return _InterlockedExchange((volatile long *)&value, val); 89 } 90 91 // The function returns the initial value. 92 int32 CompareAndSwap(int32 compareValue, int32 newValue) 93 { 94 return _InterlockedCompareExchange((volatile long *)&value, newValue, compareValue); 95 } 96 97 // Relaxed operation: there are no synchronization or ordering constraints 98 int32 LoadRelaxed() const 99 { 100 return value; 101 } 102 103 // Relaxed operation: there are no synchronization or ordering constraints 104 void StoreRelaxed(int32 val) 105 { 106 value = val; 107 } 108 109 }; 110 111 112 // 113 // Atomic pointer 114 // 115 template<typename T> 116 class AtomicPtr 117 { 118 volatile T* value; 119 120 public: 121 122 AtomicPtr() 123 : value(nullptr) 124 { 125 MT_ASSERT(IsPointerAligned(&value, sizeof(void*)), "Invalid atomic ptr alignment"); 126 } 127 128 explicit AtomicPtr(T* v) 129 : value(v) 130 { 131 MT_ASSERT(IsPointerAligned(&value, sizeof(void*)), "Invalid atomic ptr alignment"); 132 } 133 134 T* Load() const 135 { 136 return (T*)value; 137 } 138 139 // The function returns the initial value. 140 T* Store(T* val) 141 { 142 #ifdef _M_IX86 143 static_assert(sizeof(long) == sizeof(void*), "Incompatible types, _InterlockedExchange will fail"); 144 return (T*)_InterlockedExchange((volatile long *)&value, (int32)val); 145 #else 146 return (T*)_InterlockedExchangePointer((PVOID volatile *)&value, (PVOID)val); 147 #endif 148 } 149 150 // The function returns the initial value. 151 T* CompareAndSwap(T* compareValue, T* newValue) 152 { 153 #ifdef _M_IX86 154 static_assert(sizeof(long) == sizeof(void*), "Incompatible types, _InterlockedCompareExchange will fail"); 155 return (T*)_InterlockedCompareExchange((volatile long *)&value, (int32)newValue, (int32)compareValue); 156 #else 157 return (T*)_InterlockedCompareExchangePointer((PVOID volatile *)&value, (PVOID)newValue, (PVOID)compareValue); 158 #endif 159 } 160 161 // Relaxed operation: there are no synchronization or ordering constraints 162 T* LoadRelaxed() const 163 { 164 return value; 165 } 166 167 // Relaxed operation: there are no synchronization or ordering constraints 168 void StoreRelaxed(T* val) 169 { 170 value = val; 171 } 172 173 }; 174 175 176 } 177 178 179 #endif