1 | // Licensed to the .NET Foundation under one or more agreements. |
2 | // The .NET Foundation licenses this file to you under the MIT license. |
3 | // See the LICENSE file in the project root for more information. |
4 | // __forceinline implementation of the Interlocked class methods |
5 | // |
6 | |
7 | #ifndef __GCENV_INTERLOCKED_INL__ |
8 | #define __GCENV_INTERLOCKED_INL__ |
9 | |
10 | #ifdef _MSC_VER |
11 | #include <intrin.h> |
12 | #endif // _MSC_VER |
13 | |
14 | #ifndef _MSC_VER |
15 | __forceinline void Interlocked::ArmInterlockedOperationBarrier() |
16 | { |
17 | #ifdef _ARM64_ |
18 | // See PAL_ArmInterlockedOperationBarrier() in the PAL |
19 | __sync_synchronize(); |
20 | #endif // _ARM64_ |
21 | } |
22 | #endif // !_MSC_VER |
23 | |
24 | // Increment the value of the specified 32-bit variable as an atomic operation. |
25 | // Parameters: |
26 | // addend - variable to be incremented |
27 | // Return: |
28 | // The resulting incremented value |
29 | template <typename T> |
30 | __forceinline T Interlocked::Increment(T volatile *addend) |
31 | { |
32 | #ifdef _MSC_VER |
33 | static_assert(sizeof(long) == sizeof(T), "Size of long must be the same as size of T" ); |
34 | return _InterlockedIncrement((long*)addend); |
35 | #else |
36 | T result = __sync_add_and_fetch(addend, 1); |
37 | ArmInterlockedOperationBarrier(); |
38 | return result; |
39 | #endif |
40 | } |
41 | |
42 | // Decrement the value of the specified 32-bit variable as an atomic operation. |
43 | // Parameters: |
44 | // addend - variable to be decremented |
45 | // Return: |
46 | // The resulting decremented value |
47 | template <typename T> |
48 | __forceinline T Interlocked::Decrement(T volatile *addend) |
49 | { |
50 | #ifdef _MSC_VER |
51 | static_assert(sizeof(long) == sizeof(T), "Size of long must be the same as size of T" ); |
52 | return _InterlockedDecrement((long*)addend); |
53 | #else |
54 | T result = __sync_sub_and_fetch(addend, 1); |
55 | ArmInterlockedOperationBarrier(); |
56 | return result; |
57 | #endif |
58 | } |
59 | |
60 | // Set a 32-bit variable to the specified value as an atomic operation. |
61 | // Parameters: |
62 | // destination - value to be exchanged |
63 | // value - value to set the destination to |
64 | // Return: |
65 | // The previous value of the destination |
66 | template <typename T> |
67 | __forceinline T Interlocked::Exchange(T volatile *destination, T value) |
68 | { |
69 | #ifdef _MSC_VER |
70 | static_assert(sizeof(long) == sizeof(T), "Size of long must be the same as size of T" ); |
71 | return _InterlockedExchange((long*)destination, value); |
72 | #else |
73 | T result = __sync_swap(destination, value); |
74 | ArmInterlockedOperationBarrier(); |
75 | return result; |
76 | #endif |
77 | } |
78 | |
79 | // Performs an atomic compare-and-exchange operation on the specified values. |
80 | // Parameters: |
81 | // destination - value to be exchanged |
82 | // exchange - value to set the destinaton to |
83 | // comparand - value to compare the destination to before setting it to the exchange. |
84 | // The destination is set only if the destination is equal to the comparand. |
85 | // Return: |
86 | // The original value of the destination |
87 | template <typename T> |
88 | __forceinline T Interlocked::CompareExchange(T volatile *destination, T exchange, T comparand) |
89 | { |
90 | #ifdef _MSC_VER |
91 | static_assert(sizeof(long) == sizeof(T), "Size of long must be the same as size of T" ); |
92 | return _InterlockedCompareExchange((long*)destination, exchange, comparand); |
93 | #else |
94 | T result = __sync_val_compare_and_swap(destination, comparand, exchange); |
95 | ArmInterlockedOperationBarrier(); |
96 | return result; |
97 | #endif |
98 | } |
99 | |
100 | // Perform an atomic addition of two 32-bit values and return the original value of the addend. |
101 | // Parameters: |
102 | // addend - variable to be added to |
103 | // value - value to add |
104 | // Return: |
105 | // The previous value of the addend |
106 | template <typename T> |
107 | __forceinline T Interlocked::ExchangeAdd(T volatile *addend, T value) |
108 | { |
109 | #ifdef _MSC_VER |
110 | static_assert(sizeof(long) == sizeof(T), "Size of long must be the same as size of T" ); |
111 | return _InterlockedExchangeAdd((long*)addend, value); |
112 | #else |
113 | T result = __sync_fetch_and_add(addend, value); |
114 | ArmInterlockedOperationBarrier(); |
115 | return result; |
116 | #endif |
117 | } |
118 | |
119 | // Perform an atomic AND operation on the specified values values |
120 | // Parameters: |
121 | // destination - the first operand and the destination |
122 | // value - second operand |
123 | template <typename T> |
124 | __forceinline void Interlocked::And(T volatile *destination, T value) |
125 | { |
126 | #ifdef _MSC_VER |
127 | static_assert(sizeof(long) == sizeof(T), "Size of long must be the same as size of T" ); |
128 | _InterlockedAnd((long*)destination, value); |
129 | #else |
130 | __sync_and_and_fetch(destination, value); |
131 | ArmInterlockedOperationBarrier(); |
132 | #endif |
133 | } |
134 | |
135 | // Perform an atomic OR operation on the specified values values |
136 | // Parameters: |
137 | // destination - the first operand and the destination |
138 | // value - second operand |
139 | template <typename T> |
140 | __forceinline void Interlocked::Or(T volatile *destination, T value) |
141 | { |
142 | #ifdef _MSC_VER |
143 | static_assert(sizeof(long) == sizeof(T), "Size of long must be the same as size of T" ); |
144 | _InterlockedOr((long*)destination, value); |
145 | #else |
146 | __sync_or_and_fetch(destination, value); |
147 | ArmInterlockedOperationBarrier(); |
148 | #endif |
149 | } |
150 | |
151 | // Set a pointer variable to the specified value as an atomic operation. |
152 | // Parameters: |
153 | // destination - value to be exchanged |
154 | // value - value to set the destination to |
155 | // Return: |
156 | // The previous value of the destination |
157 | template <typename T> |
158 | __forceinline T Interlocked::ExchangePointer(T volatile * destination, T value) |
159 | { |
160 | #ifdef _MSC_VER |
161 | #ifdef BIT64 |
162 | return (T)(TADDR)_InterlockedExchangePointer((void* volatile *)destination, value); |
163 | #else |
164 | return (T)(TADDR)_InterlockedExchange((long volatile *)(void* volatile *)destination, (long)(void*)value); |
165 | #endif |
166 | #else |
167 | T result = (T)(TADDR)__sync_swap((void* volatile *)destination, value); |
168 | ArmInterlockedOperationBarrier(); |
169 | return result; |
170 | #endif |
171 | } |
172 | |
173 | template <typename T> |
174 | __forceinline T Interlocked::ExchangePointer(T volatile * destination, std::nullptr_t value) |
175 | { |
176 | #ifdef _MSC_VER |
177 | #ifdef BIT64 |
178 | return (T)(TADDR)_InterlockedExchangePointer((void* volatile *)destination, value); |
179 | #else |
180 | return (T)(TADDR)_InterlockedExchange((long volatile *)(void* volatile *)destination, (long)(void*)value); |
181 | #endif |
182 | #else |
183 | T result = (T)(TADDR)__sync_swap((void* volatile *)destination, value); |
184 | ArmInterlockedOperationBarrier(); |
185 | return result; |
186 | #endif |
187 | } |
188 | |
189 | // Performs an atomic compare-and-exchange operation on the specified pointers. |
190 | // Parameters: |
191 | // destination - value to be exchanged |
192 | // exchange - value to set the destinaton to |
193 | // comparand - value to compare the destination to before setting it to the exchange. |
194 | // The destination is set only if the destination is equal to the comparand. |
195 | // Return: |
196 | // The original value of the destination |
197 | template <typename T> |
198 | __forceinline T Interlocked::CompareExchangePointer(T volatile *destination, T exchange, T comparand) |
199 | { |
200 | #ifdef _MSC_VER |
201 | #ifdef BIT64 |
202 | return (T)(TADDR)_InterlockedCompareExchangePointer((void* volatile *)destination, exchange, comparand); |
203 | #else |
204 | return (T)(TADDR)_InterlockedCompareExchange((long volatile *)(void* volatile *)destination, (long)(void*)exchange, (long)(void*)comparand); |
205 | #endif |
206 | #else |
207 | T result = (T)(TADDR)__sync_val_compare_and_swap((void* volatile *)destination, comparand, exchange); |
208 | ArmInterlockedOperationBarrier(); |
209 | return result; |
210 | #endif |
211 | } |
212 | |
213 | template <typename T> |
214 | __forceinline T Interlocked::CompareExchangePointer(T volatile *destination, T exchange, std::nullptr_t comparand) |
215 | { |
216 | #ifdef _MSC_VER |
217 | #ifdef BIT64 |
218 | return (T)(TADDR)_InterlockedCompareExchangePointer((void* volatile *)destination, (void*)exchange, (void*)comparand); |
219 | #else |
220 | return (T)(TADDR)_InterlockedCompareExchange((long volatile *)(void* volatile *)destination, (long)(void*)exchange, (long)(void*)comparand); |
221 | #endif |
222 | #else |
223 | T result = (T)(TADDR)__sync_val_compare_and_swap((void* volatile *)destination, (void*)comparand, (void*)exchange); |
224 | ArmInterlockedOperationBarrier(); |
225 | return result; |
226 | #endif |
227 | } |
228 | |
229 | #endif // __GCENV_INTERLOCKED_INL__ |
230 | |