2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2010 Sam Lantinga
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
29 * If you are not an expert in concurrent lockless programming, you should
30 * only be using the atomic lock and reference counting functions in this
31 * file. In all other cases you should be protecting your data structures
34 * The list of "safe" functions to use are:
40 * Seriously, here be dragons!
42 * These operations may, or may not, actually be implemented using
43 * processor specific atomic operations. When possible they are
44 * implemented as true processor specific atomic operations. When that
45 * is not possible the are implemented using locks that *do* use the
46 * available atomic operations.
48 * All of the atomic operations that modify memory are full memory barriers.
51 #ifndef _SDL_atomic_h_
52 #define _SDL_atomic_h_
54 #include "SDL_stdinc.h"
55 #include "SDL_platform.h"
57 #include "begin_code.h"
59 /* Set up for C function definitions, even when using C++ */
67 * \name SDL AtomicLock
69 * The atomic locks are efficient spinlocks using CPU instructions,
70 * but are vulnerable to starvation and can spin forever if a thread
71 * holding a lock has been terminated. For this reason you should
72 * minimize the code executed inside an atomic lock and never do
73 * expensive things like API or system calls while holding them.
75 * The atomic locks are not safe to lock recursively.
78 * The spin lock functions and type are required and can not be
79 * emulated because they are used in the atomic emulation code.
83 typedef int SDL_SpinLock;
86 * \brief Try to lock a spin lock by setting it to a non-zero value.
88 * \param lock Points to the lock.
90 * \return SDL_TRUE if the lock succeeded, SDL_FALSE if the lock is already held.
92 extern DECLSPEC SDL_bool SDLCALL SDL_AtomicTryLock(SDL_SpinLock *lock);
95 * \brief Lock a spin lock by setting it to a non-zero value.
97 * \param lock Points to the lock.
99 extern DECLSPEC void SDLCALL SDL_AtomicLock(SDL_SpinLock *lock);
102 * \brief Unlock a spin lock by setting it to 0. Always returns immediately
104 * \param lock Points to the lock.
106 extern DECLSPEC void SDLCALL SDL_AtomicUnlock(SDL_SpinLock *lock);
108 /*@}*//*SDL AtomicLock*/
110 /* Platform specific optimized versions of the atomic functions,
111 * you can disable these by defining SDL_DISABLE_ATOMIC_INLINE
113 #ifndef SDL_DISABLE_ATOMIC_INLINE
115 #if defined(__WIN32__)
118 #define SDL_AtomicSet(a, v) _InterlockedExchange(&(a)->value, (v))
119 #define SDL_AtomicGet(a) ((a)->value)
120 #define SDL_AtomicAdd(a, v) _InterlockedExchangeAdd(&(a)->value, (v))
121 #define SDL_AtomicCAS(a, oldval, newval) (_InterlockedCompareExchange(&(a)->value, (newval), (oldval)) == (oldval))
122 #define SDL_AtomicSetPtr(a, v) (void)_InterlockedExchangePointer((a), (v))
123 #define SDL_AtomicGetPtr(a) (*(a))
125 #define SDL_AtomicCASPtr(a, oldval, newval) (_InterlockedCompareExchange((long*)(a), (long)(newval), (long)(oldval)) == (long)(oldval))
127 #define SDL_AtomicCASPtr(a, oldval, newval) (_InterlockedCompareExchangePointer((a), (newval), (oldval)) == (oldval))
130 #elif defined(__MACOSX__)
131 #include <libkern/OSAtomic.h>
133 #define SDL_AtomicSet(a, v) \
138 oldvalue = (a)->value; \
139 } while (!OSAtomicCompareAndSwap32Barrier(oldvalue, v, &(a)->value)); \
143 #define SDL_AtomicGet(a) ((a)->value)
144 #define SDL_AtomicAdd(a, v) \
149 oldvalue = (a)->value; \
150 } while (!OSAtomicCompareAndSwap32Barrier(oldvalue, oldvalue+v, &(a)->value)); \
154 #define SDL_AtomicCAS(a, oldval, newval) OSAtomicCompareAndSwap32Barrier(oldval, newval, &(a)->value)
155 #define SDL_AtomicSetPtr(a, v) (*(a) = v, OSMemoryBarrier())
156 #define SDL_AtomicGetPtr(a) (*(a))
157 #if SIZEOF_VOIDP == 4
158 #define SDL_AtomicCASPtr(a, oldval, newval) OSAtomicCompareAndSwap32Barrier((int32_t)(oldval), (int32_t)(newval), (int32_t*)(a))
159 #elif SIZEOF_VOIDP == 8
160 #define SDL_AtomicCASPtr(a, oldval, newval) OSAtomicCompareAndSwap64Barrier((int64_t)(oldval), (int64_t)(newval), (int64_t*)(a))
163 #elif defined(HAVE_GCC_ATOMICS)
165 #define SDL_AtomicSet(a, v) __sync_lock_test_and_set(&(a)->value, v)
166 #define SDL_AtomicGet(a) ((a)->value)
167 #define SDL_AtomicAdd(a, v) __sync_fetch_and_add(&(a)->value, v)
168 #define SDL_AtomicCAS(a, oldval, newval) __sync_bool_compare_and_swap(&(a)->value, oldval, newval)
169 #define SDL_AtomicSetPtr(a, v) (*(a) = v, __sync_synchronize())
170 #define SDL_AtomicGetPtr(a) (*(a))
171 #define SDL_AtomicCASPtr(a, oldval, newval) __sync_bool_compare_and_swap(a, oldval, newval)
175 #endif /* !SDL_DISABLE_ATOMIC_INLINE */
179 * \brief A type representing an atomic integer value. It is a struct
180 * so people don't accidentally use numeric operations on it.
182 #ifndef SDL_atomic_t_defined
183 typedef struct { int value; } SDL_atomic_t;
187 * \brief Set an atomic variable to a value.
189 * \return The previous value of the atomic variable.
191 #ifndef SDL_AtomicSet
192 extern DECLSPEC int SDLCALL SDL_AtomicSet(SDL_atomic_t *a, int value);
196 * \brief Get the value of an atomic variable
198 #ifndef SDL_AtomicGet
199 extern DECLSPEC int SDLCALL SDL_AtomicGet(SDL_atomic_t *a);
203 * \brief Add to an atomic variable.
205 * \return The previous value of the atomic variable.
207 #ifndef SDL_AtomicAdd
208 extern DECLSPEC int SDLCALL SDL_AtomicAdd(SDL_atomic_t *a, int value);
212 * \brief Increment an atomic variable used as a reference count.
214 #ifndef SDL_AtomicIncRef
215 extern DECLSPEC void SDLCALL SDL_AtomicIncRef(SDL_atomic_t *a);
219 * \brief Decrement an atomic variable used as a reference count.
221 * \return SDL_TRUE if the variable has reached zero after decrementing,
222 * SDL_FALSE otherwise
224 #ifndef SDL_AtomicDecRef
225 extern DECLSPEC SDL_bool SDLCALL SDL_AtomicDecRef(SDL_atomic_t *a);
229 * \brief Set an atomic variable to a new value if it is currently an old value.
231 * \return SDL_TRUE if the atomic variable was set, SDL_FALSE otherwise.
233 * \note If you don't know what this function is for, you shouldn't use it!
235 #ifndef SDL_AtomicCAS
236 extern DECLSPEC SDL_bool SDLCALL SDL_AtomicCAS(SDL_atomic_t *a, int oldval, int newval);
240 * \brief Set a pointer to a value atomically.
242 #ifndef SDL_AtomicSetPtr
243 extern DECLSPEC void SDLCALL SDL_AtomicSetPtr(void** a, void* value);
247 * \brief Get the value of a pointer atomically.
249 #ifndef SDL_AtomicGetPtr
250 extern DECLSPEC void* SDLCALL SDL_AtomicGetPtr(void** a);
254 * \brief Set a pointer to a new value if it is currently an old value.
256 * \return SDL_TRUE if the pointer was set, SDL_FALSE otherwise.
258 * \note If you don't know what this function is for, you shouldn't use it!
260 #ifndef SDL_AtomicCASPtr
261 extern DECLSPEC SDL_bool SDLCALL SDL_AtomicCASPtr(void **a, void *oldval, void *newval);
264 /* Ends C function definitions when using C++ */
271 #include "close_code.h"
273 #endif /* _SDL_atomic_h_ */
275 /* vi: set ts=4 sw=4 expandtab: */