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