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