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 
29 namespace MT
30 {
31 
32 	inline void HardwareFullMemoryBarrier()
33 	{
34 		__sync_synchronize();
35 	}
36 
37 	//
38 	// Atomic int
39 	//
40 	class AtomicInt32
41 	{
42 		volatile int32 value;
43 	public:
44 
45 		AtomicInt32()
46 			: value(0)
47 		{
48 			static_assert(sizeof(AtomicInt32) == 4, "Invalid type size");
49 			MT_ASSERT(IsPointerAligned(&value, 4), "Invalid atomic int alignment");
50 		}
51 
52 		explicit AtomicInt32(int32 v)
53 			: value(v)
54 		{
55 			static_assert(sizeof(AtomicInt32) == 4, "Invalid type size");
56 			MT_ASSERT(IsPointerAligned(&value, 4), "Invalid atomic int alignment");
57 		}
58 
59 		int32 AddFetch(int32 sum)
60 		{
61 			return __sync_add_and_fetch(&value, sum);
62 		}
63 
64 		int32 IncFetch()
65 		{
66 			return __sync_add_and_fetch(&value, 1);
67 		}
68 
69 		int32 DecFetch()
70 		{
71 			return __sync_sub_and_fetch(&value, 1);
72 		}
73 
74 		int32 Load() const
75 		{
76 			return value;
77 		}
78 
79 		int32 Store(int32 val)
80 		{
81 			return __sync_lock_test_and_set(&value, val);
82 		}
83 
84 		// The function returns the initial value.
85 		int32 CompareAndSwap(int32 compareValue, int32 newValue)
86 		{
87 			return __sync_val_compare_and_swap(&value, compareValue, newValue);
88 		}
89 
90 		// Relaxed operation: there are no synchronization or ordering constraints
91 		int32 LoadRelaxed() const
92 		{
93 			return value;
94 		}
95 
96 		// Relaxed operation: there are no synchronization or ordering constraints
97 		void StoreRelaxed(int32 val)
98 		{
99 			value = val;
100 		}
101 
102 
103 	};
104 
105 
106 	//
107 	// Atomic pointer
108 	//
109 	template<typename T>
110 	class AtomicPtr
111 	{
112 		volatile T* value;
113 
114 	public:
115 
116 		AtomicPtr()
117 			: value(nullptr)
118 		{
119 			MT_ASSERT(IsPointerAligned(&value, sizeof(void*)), "Invalid atomic ptr alignment");
120 		}
121 
122 		explicit AtomicPtr(T* v)
123 			: value(v)
124 		{
125 			MT_ASSERT(IsPointerAligned(&value, sizeof(void*)), "Invalid atomic ptr alignment");
126 		}
127 
128 		T* Load() const
129 		{
130 			return (T*)value;
131 		}
132 
133 		// The function returns the initial value.
134 		T* Store(T* val)
135 		{
136 			void* r = __sync_lock_test_and_set((void**)&value, (void*)val);
137 			return (T*)r;
138 		}
139 
140 		// The function returns the initial value.
141 		T* CompareAndSwap(T* compareValue, T* newValue)
142 		{
143 			void* r = __sync_val_compare_and_swap((void**)&value, (void*)compareValue, (void*)newValue);
144 			return (T*)r;
145 		}
146 
147 		// Relaxed operation: there are no synchronization or ordering constraints
148 		T* LoadRelaxed() const
149 		{
150 			return value;
151 		}
152 
153 		// Relaxed operation: there are no synchronization or ordering constraints
154 		void StoreRelaxed(T* val)
155 		{
156 			value = val;
157 		}
158 
159 	};
160 
161 
162 }
163 
164 #endif