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 <MTConfig.h> 29 #include <intrin.h> 30 #include <cstdint> 31 #include <type_traits> 32 #include <xmmintrin.h> 33 34 namespace MT 35 { 36 // 37 // Full memory barrier 38 // 39 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 40 inline void HardwareFullMemoryBarrier() 41 { 42 _mm_mfence(); 43 } 44 45 // 46 // Signals to the processor to give resources to threads that are waiting for them. 47 // 48 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 49 inline void YieldCpu() 50 { 51 _mm_pause(); 52 } 53 54 55 // 56 // Atomic int (pod type) 57 // 58 // You must use this type when you need to declare static variable instead of AtomicInt32 59 // 60 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 61 struct AtomicInt32Base 62 { 63 volatile int32 _value; 64 65 // The function returns the resulting added value. 66 int32 AddFetch(int32 sum) 67 { 68 return _InterlockedExchangeAdd((volatile long*)&_value, sum) + sum; 69 } 70 71 // The function returns the resulting incremented value. 72 int32 IncFetch() 73 { 74 return _InterlockedIncrement((volatile long*)&_value); 75 } 76 77 // The function returns the resulting decremented value. 78 int32 DecFetch() 79 { 80 return _InterlockedDecrement((volatile long*)&_value); 81 } 82 83 int32 Load() const 84 { 85 return _value; 86 } 87 88 // The function returns the initial value. 89 int32 Store(int32 val) 90 { 91 return _InterlockedExchange((volatile long*)&_value, val); 92 } 93 94 // The function returns the initial value. 95 int32 CompareAndSwap(int32 compareValue, int32 newValue) 96 { 97 return _InterlockedCompareExchange((volatile long*)&_value, newValue, compareValue); 98 } 99 100 // Relaxed operation: there are no synchronization or ordering constraints 101 int32 LoadRelaxed() const 102 { 103 return _value; 104 } 105 106 // Relaxed operation: there are no synchronization or ordering constraints 107 void StoreRelaxed(int32 val) 108 { 109 _value = val; 110 } 111 112 }; 113 114 115 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 116 static_assert(sizeof(int32) == sizeof(long), "Incompatible types, Interlocked* will fail."); 117 118 119 120 // 121 // Atomic pointer (pod type) 122 // 123 // You must use this type when you need to declare static variable instead of AtomicInt32 124 // 125 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 126 struct AtomicPtrBase 127 { 128 volatile const void* _value; 129 130 void* Load() const 131 { 132 return (void*)_value; 133 } 134 135 // The function returns the initial value. 136 const void* Store(const void* val) 137 { 138 #ifndef MT_PTR64 139 static_assert(sizeof(long) == sizeof(void*), "Incompatible types, _InterlockedExchange will fail"); 140 return (void*)_InterlockedExchange((volatile long*)&_value, (long)val); 141 #else 142 return _InterlockedExchangePointer((void* volatile*)&_value, (void*)val); 143 #endif 144 } 145 146 // The function returns the initial value. 147 const void* CompareAndSwap(const void* compareValue, const void* newValue) 148 { 149 #ifndef MT_PTR64 150 static_assert(sizeof(long) == sizeof(void*), "Incompatible types, _InterlockedCompareExchange will fail"); 151 return (void*)_InterlockedCompareExchange((volatile long*)&_value, (long)newValue, (long)compareValue); 152 #else 153 return _InterlockedCompareExchangePointer((void* volatile*)&_value, (void*)newValue, (void*)compareValue); 154 #endif 155 } 156 157 // Relaxed operation: there are no synchronization or ordering constraints 158 const void* LoadRelaxed() const 159 { 160 return (const void*)_value; 161 } 162 163 // Relaxed operation: there are no synchronization or ordering constraints 164 void StoreRelaxed(const void* val) 165 { 166 _value = val; 167 } 168 169 }; 170 171 172 173 } 174 175 176 #endif 177