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