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