Mercurial > sdl-ios-xcode
comparison include/SDL_atomic.h @ 5097:dceec93471e7
Improvements based on feedback from Anthony Williams
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Tue, 25 Jan 2011 17:40:06 -0800 |
parents | c2539ff054c8 |
children | e4301cde4de1 |
comparison
equal
deleted
inserted
replaced
5096:124cda437b07 | 5097:dceec93471e7 |
---|---|
36 * SDL_AtomicUnlock() | 36 * SDL_AtomicUnlock() |
37 * SDL_AtomicIncRef() | 37 * SDL_AtomicIncRef() |
38 * SDL_AtomicDecRef() | 38 * SDL_AtomicDecRef() |
39 * | 39 * |
40 * Seriously, here be dragons! | 40 * Seriously, here be dragons! |
41 * | 41 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
42 * These operations may, or may not, actually be implemented using | 42 * |
43 * You can find out a little more about lockless programming and the | |
44 * subtle issues that can arise here: | |
45 * http://msdn.microsoft.com/en-us/library/ee418650%28v=vs.85%29.aspx | |
46 * | |
47 * These operations may or may not actually be implemented using | |
43 * processor specific atomic operations. When possible they are | 48 * processor specific atomic operations. When possible they are |
44 * implemented as true processor specific atomic operations. When that | 49 * implemented as true processor specific atomic operations. When that |
45 * is not possible the are implemented using locks that *do* use the | 50 * is not possible the are implemented using locks that *do* use the |
46 * available atomic operations. | 51 * available atomic operations. |
47 * | 52 * |
112 */ | 117 */ |
113 extern DECLSPEC void SDLCALL SDL_AtomicUnlock(SDL_SpinLock *lock); | 118 extern DECLSPEC void SDLCALL SDL_AtomicUnlock(SDL_SpinLock *lock); |
114 | 119 |
115 /*@}*//*SDL AtomicLock*/ | 120 /*@}*//*SDL AtomicLock*/ |
116 | 121 |
122 | |
123 /* The compiler barrier prevents the compiler from reordering | |
124 reads and writes to globally visible variables across the call. | |
125 */ | |
126 #ifdef _MSC_VER | |
127 void _ReadWriteBarrier(void); | |
128 #pragma intrinsic(_ReadWriteBarrier) | |
129 #define SDL_CompilerBarrier() _ReadWriteBarrier() | |
130 #elif __GNUC__ | |
131 #define SDL_CompilerBarrier() __asm__ __volatile__ ("" : : : "memory") | |
132 #else | |
133 #define SDL_CompilerBarrier() \ | |
134 ({ SDL_SpinLock _tmp = 0; SDL_AtomicLock(&_tmp); SDL_AtomicUnlock(&_tmp); }) | |
135 #endif | |
136 | |
117 /* Platform specific optimized versions of the atomic functions, | 137 /* Platform specific optimized versions of the atomic functions, |
118 * you can disable these by defining SDL_DISABLE_ATOMIC_INLINE | 138 * you can disable these by defining SDL_DISABLE_ATOMIC_INLINE |
119 */ | 139 */ |
120 #ifndef SDL_DISABLE_ATOMIC_INLINE | 140 #ifndef SDL_DISABLE_ATOMIC_INLINE |
121 | 141 |
122 #if defined(HAVE_MSC_ATOMICS) | 142 #if HAVE_MSC_ATOMICS |
123 | 143 |
124 #define SDL_AtomicSet(a, v) _InterlockedExchange((long*)&(a)->value, (v)) | 144 #define SDL_AtomicSet(a, v) _InterlockedExchange((long*)&(a)->value, (v)) |
125 #define SDL_AtomicGet(a) ((a)->value) | |
126 #define SDL_AtomicAdd(a, v) _InterlockedExchangeAdd((long*)&(a)->value, (v)) | 145 #define SDL_AtomicAdd(a, v) _InterlockedExchangeAdd((long*)&(a)->value, (v)) |
127 #define SDL_AtomicCAS(a, oldval, newval) (_InterlockedCompareExchange((long*)&(a)->value, (newval), (oldval)) == (oldval)) | 146 #define SDL_AtomicCAS(a, oldval, newval) (_InterlockedCompareExchange((long*)&(a)->value, (newval), (oldval)) == (oldval)) |
128 #define SDL_AtomicSetPtr(a, v) (void)_InterlockedExchangePointer((a), (v)) | 147 #define SDL_AtomicSetPtr(a, v) _InterlockedExchangePointer((a), (v)) |
129 #define SDL_AtomicGetPtr(a) (*(a)) | |
130 #if _M_IX86 | 148 #if _M_IX86 |
131 #define SDL_AtomicCASPtr(a, oldval, newval) (_InterlockedCompareExchange((long*)(a), (long)(newval), (long)(oldval)) == (long)(oldval)) | 149 #define SDL_AtomicCASPtr(a, oldval, newval) (_InterlockedCompareExchange((long*)(a), (long)(newval), (long)(oldval)) == (long)(oldval)) |
132 #else | 150 #else |
133 #define SDL_AtomicCASPtr(a, oldval, newval) (_InterlockedCompareExchangePointer((a), (newval), (oldval)) == (oldval)) | 151 #define SDL_AtomicCASPtr(a, oldval, newval) (_InterlockedCompareExchangePointer((a), (newval), (oldval)) == (oldval)) |
134 #endif | 152 #endif |
135 | 153 |
136 #elif defined(__MACOSX__) | 154 #elif __MACOSX__ |
137 #include <libkern/OSAtomic.h> | 155 #include <libkern/OSAtomic.h> |
138 | 156 |
139 #define SDL_AtomicSet(a, v) \ | 157 #define SDL_AtomicCAS(a, oldval, newval) OSAtomicCompareAndSwap32Barrier((oldval), (newval), &(a)->value) |
140 ({ \ | |
141 int oldvalue; \ | |
142 \ | |
143 do { \ | |
144 oldvalue = (a)->value; \ | |
145 } while (!OSAtomicCompareAndSwap32Barrier(oldvalue, v, &(a)->value)); \ | |
146 \ | |
147 oldvalue; \ | |
148 }) | |
149 #define SDL_AtomicGet(a) ((a)->value) | |
150 #define SDL_AtomicAdd(a, v) \ | |
151 ({ \ | |
152 int oldvalue; \ | |
153 \ | |
154 do { \ | |
155 oldvalue = (a)->value; \ | |
156 } while (!OSAtomicCompareAndSwap32Barrier(oldvalue, oldvalue+v, &(a)->value)); \ | |
157 \ | |
158 oldvalue; \ | |
159 }) | |
160 #define SDL_AtomicCAS(a, oldval, newval) OSAtomicCompareAndSwap32Barrier(oldval, newval, &(a)->value) | |
161 #define SDL_AtomicSetPtr(a, v) (*(a) = v, OSMemoryBarrier()) | |
162 #define SDL_AtomicGetPtr(a) (*(a)) | |
163 #if SIZEOF_VOIDP == 4 | 158 #if SIZEOF_VOIDP == 4 |
164 #define SDL_AtomicCASPtr(a, oldval, newval) OSAtomicCompareAndSwap32Barrier((int32_t)(oldval), (int32_t)(newval), (int32_t*)(a)) | 159 #define SDL_AtomicCASPtr(a, oldval, newval) OSAtomicCompareAndSwap32Barrier((int32_t)(oldval), (int32_t)(newval), (int32_t*)(a)) |
165 #elif SIZEOF_VOIDP == 8 | 160 #elif SIZEOF_VOIDP == 8 |
166 #define SDL_AtomicCASPtr(a, oldval, newval) OSAtomicCompareAndSwap64Barrier((int64_t)(oldval), (int64_t)(newval), (int64_t*)(a)) | 161 #define SDL_AtomicCASPtr(a, oldval, newval) OSAtomicCompareAndSwap64Barrier((int64_t)(oldval), (int64_t)(newval), (int64_t*)(a)) |
167 #endif | 162 #endif |
168 | 163 |
169 #elif defined(HAVE_GCC_ATOMICS) | 164 #elif HAVE_GCC_ATOMICS |
170 | 165 |
171 #define SDL_AtomicSet(a, v) __sync_lock_test_and_set(&(a)->value, v) | 166 #define SDL_AtomicSet(a, v) __sync_lock_test_and_set(&(a)->value, v) |
172 #define SDL_AtomicGet(a) ((a)->value) | |
173 #define SDL_AtomicAdd(a, v) __sync_fetch_and_add(&(a)->value, v) | 167 #define SDL_AtomicAdd(a, v) __sync_fetch_and_add(&(a)->value, v) |
168 #define SDL_AtomicSetPtr(a, v) __sync_lock_test_and_set(a, v) | |
174 #define SDL_AtomicCAS(a, oldval, newval) __sync_bool_compare_and_swap(&(a)->value, oldval, newval) | 169 #define SDL_AtomicCAS(a, oldval, newval) __sync_bool_compare_and_swap(&(a)->value, oldval, newval) |
175 #define SDL_AtomicSetPtr(a, v) (*(a) = v, __sync_synchronize()) | |
176 #define SDL_AtomicGetPtr(a) (*(a)) | |
177 #define SDL_AtomicCASPtr(a, oldval, newval) __sync_bool_compare_and_swap(a, oldval, newval) | 170 #define SDL_AtomicCASPtr(a, oldval, newval) __sync_bool_compare_and_swap(a, oldval, newval) |
178 | 171 |
179 #endif | 172 #endif |
180 | 173 |
181 #endif /* !SDL_DISABLE_ATOMIC_INLINE */ | 174 #endif /* !SDL_DISABLE_ATOMIC_INLINE */ |
193 * \brief Set an atomic variable to a value. | 186 * \brief Set an atomic variable to a value. |
194 * | 187 * |
195 * \return The previous value of the atomic variable. | 188 * \return The previous value of the atomic variable. |
196 */ | 189 */ |
197 #ifndef SDL_AtomicSet | 190 #ifndef SDL_AtomicSet |
198 extern DECLSPEC int SDLCALL SDL_AtomicSet(SDL_atomic_t *a, int value); | 191 #define SDL_AtomicSet(a, v) \ |
192 ({ \ | |
193 int _value; \ | |
194 do { \ | |
195 _value = (a)->value; \ | |
196 } while (!SDL_AtomicCAS(a, _value, (v))); \ | |
197 _value; \ | |
198 }) | |
199 #endif | 199 #endif |
200 | 200 |
201 /** | 201 /** |
202 * \brief Get the value of an atomic variable | 202 * \brief Get the value of an atomic variable |
203 */ | 203 */ |
204 #ifndef SDL_AtomicGet | 204 #ifndef SDL_AtomicGet |
205 extern DECLSPEC int SDLCALL SDL_AtomicGet(SDL_atomic_t *a); | 205 #define SDL_AtomicGet(a) \ |
206 #endif | 206 ({ \ |
207 | 207 int _value = (a)->value; \ |
208 /** | 208 SDL_CompilerBarrier(); \ |
209 * \brief Add to an atomic variable. | 209 _value; \ |
210 }) | |
211 #endif | |
212 | |
213 /** | |
214 * \brief Add to an atomic variable. | |
210 * | 215 * |
211 * \return The previous value of the atomic variable. | 216 * \return The previous value of the atomic variable. |
217 * | |
218 * \note This same style can be used for any number operation | |
212 */ | 219 */ |
213 #ifndef SDL_AtomicAdd | 220 #ifndef SDL_AtomicAdd |
214 extern DECLSPEC int SDLCALL SDL_AtomicAdd(SDL_atomic_t *a, int value); | 221 #define SDL_AtomicAdd(a, v) \ |
222 ({ \ | |
223 int _value; \ | |
224 do { \ | |
225 _value = (a)->value; \ | |
226 } while (!SDL_AtomicCAS(a, _value, (_value + (v)))); \ | |
227 _value; \ | |
228 }) | |
215 #endif | 229 #endif |
216 | 230 |
217 /** | 231 /** |
218 * \brief Increment an atomic variable used as a reference count. | 232 * \brief Increment an atomic variable used as a reference count. |
219 */ | 233 */ |
220 #ifndef SDL_AtomicIncRef | 234 #ifndef SDL_AtomicIncRef |
221 extern DECLSPEC void SDLCALL SDL_AtomicIncRef(SDL_atomic_t *a); | 235 #define SDL_AtomicIncRef(a) SDL_AtomicAdd(a, 1) |
222 #endif | 236 #endif |
223 | 237 |
224 /** | 238 /** |
225 * \brief Decrement an atomic variable used as a reference count. | 239 * \brief Decrement an atomic variable used as a reference count. |
226 * | 240 * |
227 * \return SDL_TRUE if the variable has reached zero after decrementing, | 241 * \return SDL_TRUE if the variable reached zero after decrementing, |
228 * SDL_FALSE otherwise | 242 * SDL_FALSE otherwise |
229 */ | 243 */ |
230 #ifndef SDL_AtomicDecRef | 244 #ifndef SDL_AtomicDecRef |
231 extern DECLSPEC SDL_bool SDLCALL SDL_AtomicDecRef(SDL_atomic_t *a); | 245 #define SDL_AtomicDecRef(a) (SDL_AtomicAdd(a, -1) == 1) |
232 #endif | 246 #endif |
233 | 247 |
234 /** | 248 /** |
235 * \brief Set an atomic variable to a new value if it is currently an old value. | 249 * \brief Set an atomic variable to a new value if it is currently an old value. |
236 * | 250 * |
237 * \return SDL_TRUE if the atomic variable was set, SDL_FALSE otherwise. | 251 * \return SDL_TRUE if the atomic variable was set, SDL_FALSE otherwise. |
238 * | 252 * |
239 * \note If you don't know what this function is for, you shouldn't use it! | 253 * \note If you don't know what this function is for, you shouldn't use it! |
240 */ | 254 */ |
241 #ifndef SDL_AtomicCAS | 255 #ifndef SDL_AtomicCAS |
242 extern DECLSPEC SDL_bool SDLCALL SDL_AtomicCAS(SDL_atomic_t *a, int oldval, int newval); | 256 #define SDL_AtomicCAS SDL_AtomicCAS_ |
243 #endif | 257 #endif |
258 extern DECLSPEC SDL_bool SDLCALL SDL_AtomicCAS_(SDL_atomic_t *a, int oldval, int newval); | |
244 | 259 |
245 /** | 260 /** |
246 * \brief Set a pointer to a value atomically. | 261 * \brief Set a pointer to a value atomically. |
262 * | |
263 * \return The previous value of the pointer. | |
247 */ | 264 */ |
248 #ifndef SDL_AtomicSetPtr | 265 #ifndef SDL_AtomicSetPtr |
249 extern DECLSPEC void SDLCALL SDL_AtomicSetPtr(void** a, void* value); | 266 #define SDL_AtomicSetPtr(a, v) \ |
267 ({ \ | |
268 void* _value; \ | |
269 do { \ | |
270 _value = *(a); \ | |
271 } while (!SDL_AtomicCASPtr(a, _value, (v))); \ | |
272 _value; \ | |
273 }) | |
250 #endif | 274 #endif |
251 | 275 |
252 /** | 276 /** |
253 * \brief Get the value of a pointer atomically. | 277 * \brief Get the value of a pointer atomically. |
254 */ | 278 */ |
255 #ifndef SDL_AtomicGetPtr | 279 #ifndef SDL_AtomicGetPtr |
256 extern DECLSPEC void* SDLCALL SDL_AtomicGetPtr(void** a); | 280 #define SDL_AtomicGetPtr(a) \ |
281 ({ \ | |
282 void* _value = *(a); \ | |
283 SDL_CompilerBarrier(); \ | |
284 _value; \ | |
285 }) | |
257 #endif | 286 #endif |
258 | 287 |
259 /** | 288 /** |
260 * \brief Set a pointer to a new value if it is currently an old value. | 289 * \brief Set a pointer to a new value if it is currently an old value. |
261 * | 290 * |
262 * \return SDL_TRUE if the pointer was set, SDL_FALSE otherwise. | 291 * \return SDL_TRUE if the pointer was set, SDL_FALSE otherwise. |
263 * | 292 * |
264 * \note If you don't know what this function is for, you shouldn't use it! | 293 * \note If you don't know what this function is for, you shouldn't use it! |
265 */ | 294 */ |
266 #ifndef SDL_AtomicCASPtr | 295 #ifndef SDL_AtomicCASPtr |
267 extern DECLSPEC SDL_bool SDLCALL SDL_AtomicCASPtr(void **a, void *oldval, void *newval); | 296 #define SDL_AtomicCASPtr SDL_AtomicCASPtr_ |
268 #endif | 297 #endif |
298 extern DECLSPEC SDL_bool SDLCALL SDL_AtomicCASPtr_(void **a, void *oldval, void *newval); | |
269 | 299 |
270 /* Ends C function definitions when using C++ */ | 300 /* Ends C function definitions when using C++ */ |
271 #ifdef __cplusplus | 301 #ifdef __cplusplus |
272 /* *INDENT-OFF* */ | 302 /* *INDENT-OFF* */ |
273 } | 303 } |