1 krisbash 1.1 #ifndef _pal_atomic_h
2 #define _pal_atomic_h
3
4 #ifdef _MSC_VER
5 #pragma prefast(push)
6 #pragma prefast(disable:28251)
7 #pragma prefast(disable:28252)
8 #pragma prefast(disable:28253)
9 #include <intrin.h>
10 #pragma prefast(pop)
11 #endif
12
13 #include <pal/palcommon.h>
14
15 #if !defined(CONFIG_HAVE_ATOMIC_INTRINSICS)
16 #if defined(PAL_HAVE_PTHREADS)
17 # include <pthread.h>
18 #endif
19 #if defined(PAL_HAVE_POSIX)
20 # include <sys/types.h>
21 # include <unistd.h>
22 krisbash 1.1 #endif
23 #endif
24
25 PAL_BEGIN_EXTERNC
26
27 #if !defined(CONFIG_HAVE_ATOMIC_INTRINSICS)
28
29 #define PAL_ATOMIC_LOCKS_SIZE 64
30
31 extern PAL_Boolean __palInitialized;
32 extern pthread_mutex_t __atomicInitLock;
33 extern pthread_mutex_t __atomicLocks[PAL_ATOMIC_LOCKS_SIZE];
34
35 PAL_INLINE void __AcquireLock(pthread_mutex_t *lock);
36 PAL_INLINE void __ReleaseLock(pthread_mutex_t *lock);
37
38 PAL_INLINE void __ForkHandlerHelper(PAL_Boolean acquire)
39 {
40 int i = 0;
41 for(i = 0; i < PAL_ATOMIC_LOCKS_SIZE; i++)
42 {
43 krisbash 1.1 if(acquire)
44 __AcquireLock(&(__atomicLocks[i]));
45 else
46 __ReleaseLock(&(__atomicLocks[i]));
47 }
48
49 if(acquire)
50 {
51 pthread_mutex_lock(&__atomicInitLock);
52 }
53 else
54 {
55 pthread_mutex_unlock(&__atomicInitLock);
56 }
57 }
58
59 PAL_INLINE void __PrepareForkHandler(void)
60 {
61 __ForkHandlerHelper(PAL_TRUE);
62 }
63
64 krisbash 1.1 PAL_INLINE void __ParentForkHandler(void)
65 {
66 __ForkHandlerHelper(PAL_FALSE);
67 }
68
69 PAL_INLINE void __ChildForkHandler(void)
70 {
71 __ForkHandlerHelper(PAL_FALSE);
72 }
73
74 PAL_INLINE void __AcquireLock(pthread_mutex_t *lock)
75 {
76 if(__palInitialized == PAL_FALSE)
77 {
78 pthread_mutex_lock(&__atomicInitLock);
79
80 if(__palInitialized == PAL_FALSE)
81 {
82 pthread_atfork(__PrepareForkHandler, __ParentForkHandler, __ChildForkHandler);
83 __palInitialized = PAL_TRUE;
84 }
85 krisbash 1.1
86 pthread_mutex_unlock(&__atomicInitLock);
87 }
88
89 pthread_mutex_lock(lock);
90 }
91
92 PAL_INLINE void __ReleaseLock(pthread_mutex_t *lock)
93 {
94 pthread_mutex_unlock(lock);
95 }
96
97 #define __AtomicLockToUse(x) (&(__atomicLocks[(((unsigned)(((ptrdiff_t)(x)) >> 2)) % PAL_ATOMIC_LOCKS_SIZE)]))
98
99 PAL_INLINE void __AcquireAtomicLock(_In_ volatile ptrdiff_t* x)
100 {
101 __AcquireLock(__AtomicLockToUse(x));
102 }
103
104 PAL_INLINE void __ReleaseAtomicLock(_In_ volatile ptrdiff_t* x)
105 {
106 krisbash 1.1 __ReleaseLock(__AtomicLockToUse(x));
107 }
108
109 #endif
110
111 PAL_INLINE ptrdiff_t Atomic_Read(
112 _Inout_ volatile ptrdiff_t* x)
113 {
114 #if defined(_MSC_VER)
115 return *x;
116 #elif !defined(CONFIG_HAVE_ATOMIC_INTRINSICS)
117 ptrdiff_t retVal = 0;
118 __AcquireAtomicLock(x);
119 retVal = *x;
120 __ReleaseAtomicLock(x);
121 return retVal;
122 #else
123 return __sync_add_and_fetch(x, 0);
124 #endif
125 }
126
127 krisbash 1.1
128 PAL_INLINE ptrdiff_t Atomic_Inc(
129 _Inout_ volatile ptrdiff_t* x)
130 {
131 #if defined(_MSC_VER)
132 # if defined(_WIN64)
133 return InterlockedIncrement64(x);
134 # else
135 return InterlockedIncrement((volatile long *)x);
136 # endif
137 #elif !defined(CONFIG_HAVE_ATOMIC_INTRINSICS)
138 ptrdiff_t retVal = 0;
139 __AcquireAtomicLock(x);
140 retVal = *x;
141 retVal++;
142 *x = retVal;
143 __ReleaseAtomicLock(x);
144 return retVal;
145 #else
146 return __sync_add_and_fetch(x, 1);
147 #endif
148 krisbash 1.1 }
149
150 PAL_INLINE ptrdiff_t Atomic_Dec(
151 _Inout_ volatile ptrdiff_t* x)
152 {
153 #if defined(_MSC_VER)
154 # if defined(_WIN64)
155 return InterlockedDecrement64(x);
156 # else
157 return InterlockedDecrement((volatile long *)x);
158 # endif
159 #elif !defined(CONFIG_HAVE_ATOMIC_INTRINSICS)
160 ptrdiff_t retVal = 0;
161 __AcquireAtomicLock(x);
162 retVal = *x;
163 retVal--;
164 *x = retVal;
165 __ReleaseAtomicLock(x);
166 return retVal;
167 #else
168 return __sync_sub_and_fetch(x, 1);
169 krisbash 1.1 #endif
170 }
171
172 PAL_INLINE ptrdiff_t Atomic_CompareAndSwap(
173 _Inout_ volatile ptrdiff_t* dest,
174 _In_ ptrdiff_t comparand,
175 _In_ ptrdiff_t newValue)
176 {
177 #if defined(_MSC_VER)
178 return (ptrdiff_t)InterlockedCompareExchangePointer(
179 (PVOID*)dest, (PVOID)newValue, (PVOID)comparand);
180 #elif !defined(CONFIG_HAVE_ATOMIC_INTRINSICS)
181 ptrdiff_t retVal = 0;
182 __AcquireAtomicLock(dest);
183 retVal = *dest;
184 if(retVal == comparand)
185 {
186 *dest = newValue;
187 }
188 __ReleaseAtomicLock(dest);
189 return retVal;
190 krisbash 1.1 #else
191 return __sync_val_compare_and_swap(dest, comparand, newValue);
192 #endif
193 }
194
195 PAL_INLINE ptrdiff_t Atomic_Swap(
196 _Inout_ volatile ptrdiff_t* dest,
197 _In_ ptrdiff_t newValue)
198 {
199 #if defined(_MSC_VER)
200 return (ptrdiff_t)InterlockedExchangePointer((PVOID*)dest, (PVOID)newValue);
201 #elif !defined(CONFIG_HAVE_ATOMIC_INTRINSICS)
202 ptrdiff_t retVal = 0;
203 __AcquireAtomicLock(dest);
204 retVal = *dest;
205 *dest = newValue;
206 __ReleaseAtomicLock(dest);
207 return retVal;
208 #else
209 return __sync_lock_test_and_set(dest, newValue);
210 #endif
211 krisbash 1.1 }
212
213 PAL_INLINE ptrdiff_t Atomic_Add(
214 _Inout_ volatile ptrdiff_t* x,
215 ptrdiff_t value)
216 {
217 #if defined(_MSC_VER)
218 # if defined(_WIN64)
219 return InterlockedAdd64(x, value);
220 # else
221 return InterlockedExchangeAdd((volatile long *)x, value) + value;
222 # endif
223 #elif !defined(CONFIG_HAVE_ATOMIC_INTRINSICS)
224 ptrdiff_t retVal = 0;
225 __AcquireAtomicLock(x);
226 retVal = *x;
227 retVal = retVal + value;
228 *x = retVal;
229 __ReleaseAtomicLock(x);
230 return retVal;
231 #else
232 krisbash 1.1 return __sync_add_and_fetch(x, value);
233 #endif
234 }
235
236 PAL_INLINE ptrdiff_t Atomic_And(
237 _Inout_ volatile ptrdiff_t* x,
238 ptrdiff_t value)
239 {
240 #if defined(_MSC_VER)
241 # if defined(_WIN64)
242 return _InterlockedAnd64(x, value) & value;
243 # else
244 return _InterlockedAnd((volatile long *)x, value) & value;
245 # endif
246 #elif !defined(CONFIG_HAVE_ATOMIC_INTRINSICS)
247 ptrdiff_t retVal = 0;
248 __AcquireAtomicLock(x);
249 retVal = *x;
250 retVal = retVal & value;
251 *x = retVal;
252 __ReleaseAtomicLock(x);
253 krisbash 1.1 return retVal;
254 #else
255 return __sync_and_and_fetch(x, value);
256 #endif
257 }
258
259 /*
260 **==============================================================================
261 **
262 ** NonX86MemoryBarrier macro
263 **
264 **==============================================================================
265 */
266 #ifdef _MSC_VER
267 # if defined(_M_IX86) || defined(_M_AMD64)
268 # define NonX86MemoryBarrier() ((void)0)
269 # else
270 # define NonX86MemoryBarrier() MemoryBarrier()
271 # endif
272 #else /* !defined(_MSC_VER) */
273 # if defined(__i386__) || defined(__amd64__)
274 krisbash 1.1 # define NonX86MemoryBarrier() ((void)0)
275 # elif defined(CONFIG_HAVE_SYNC_SYNCHRONIZE)
276 # define NonX86MemoryBarrier() __sync_synchronize()
277 # else
278 extern volatile ptrdiff_t __memoryBarrierVar;
279 # define NonX86MemoryBarrier() ((void)Atomic_Swap(&__memoryBarrierVar, 0))
280 # endif
281 #endif
282
283 PAL_END_EXTERNC
284
285 #endif /* _pal_atomic_h */
|