SDL standard library
Embed:
(wiki syntax)
Show/hide line numbers
SDL_atomic.h
Go to the documentation of this file.
00001 /* 00002 Simple DirectMedia Layer 00003 Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org> 00004 00005 This software is provided 'as-is', without any express or implied 00006 warranty. In no event will the authors be held liable for any damages 00007 arising from the use of this software. 00008 00009 Permission is granted to anyone to use this software for any purpose, 00010 including commercial applications, and to alter it and redistribute it 00011 freely, subject to the following restrictions: 00012 00013 1. The origin of this software must not be misrepresented; you must not 00014 claim that you wrote the original software. If you use this software 00015 in a product, an acknowledgment in the product documentation would be 00016 appreciated but is not required. 00017 2. Altered source versions must be plainly marked as such, and must not be 00018 misrepresented as being the original software. 00019 3. This notice may not be removed or altered from any source distribution. 00020 */ 00021 00022 /** 00023 * \file SDL_atomic.h 00024 * 00025 * Atomic operations. 00026 * 00027 * IMPORTANT: 00028 * If you are not an expert in concurrent lockless programming, you should 00029 * only be using the atomic lock and reference counting functions in this 00030 * file. In all other cases you should be protecting your data structures 00031 * with full mutexes. 00032 * 00033 * The list of "safe" functions to use are: 00034 * SDL_AtomicLock() 00035 * SDL_AtomicUnlock() 00036 * SDL_AtomicIncRef() 00037 * SDL_AtomicDecRef() 00038 * 00039 * Seriously, here be dragons! 00040 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 00041 * 00042 * You can find out a little more about lockless programming and the 00043 * subtle issues that can arise here: 00044 * http://msdn.microsoft.com/en-us/library/ee418650%28v=vs.85%29.aspx 00045 * 00046 * There's also lots of good information here: 00047 * http://www.1024cores.net/home/lock-free-algorithms 00048 * http://preshing.com/ 00049 * 00050 * These operations may or may not actually be implemented using 00051 * processor specific atomic operations. When possible they are 00052 * implemented as true processor specific atomic operations. When that 00053 * is not possible the are implemented using locks that *do* use the 00054 * available atomic operations. 00055 * 00056 * All of the atomic operations that modify memory are full memory barriers. 00057 */ 00058 00059 #ifndef _SDL_atomic_h_ 00060 #define _SDL_atomic_h_ 00061 00062 #include "SDL_stdinc.h" 00063 #include "SDL_platform.h" 00064 00065 #include "begin_code.h" 00066 00067 /* Set up for C function definitions, even when using C++ */ 00068 #ifdef __cplusplus 00069 extern "C" { 00070 #endif 00071 00072 /** 00073 * \name SDL AtomicLock 00074 * 00075 * The atomic locks are efficient spinlocks using CPU instructions, 00076 * but are vulnerable to starvation and can spin forever if a thread 00077 * holding a lock has been terminated. For this reason you should 00078 * minimize the code executed inside an atomic lock and never do 00079 * expensive things like API or system calls while holding them. 00080 * 00081 * The atomic locks are not safe to lock recursively. 00082 * 00083 * Porting Note: 00084 * The spin lock functions and type are required and can not be 00085 * emulated because they are used in the atomic emulation code. 00086 */ 00087 /* @{ */ 00088 00089 typedef int SDL_SpinLock; 00090 00091 /** 00092 * \brief Try to lock a spin lock by setting it to a non-zero value. 00093 * 00094 * \param lock Points to the lock. 00095 * 00096 * \return SDL_TRUE if the lock succeeded, SDL_FALSE if the lock is already held. 00097 */ 00098 extern DECLSPEC SDL_bool SDLCALL SDL_AtomicTryLock(SDL_SpinLock *lock); 00099 00100 /** 00101 * \brief Lock a spin lock by setting it to a non-zero value. 00102 * 00103 * \param lock Points to the lock. 00104 */ 00105 extern DECLSPEC void SDLCALL SDL_AtomicLock(SDL_SpinLock *lock); 00106 00107 /** 00108 * \brief Unlock a spin lock by setting it to 0. Always returns immediately 00109 * 00110 * \param lock Points to the lock. 00111 */ 00112 extern DECLSPEC void SDLCALL SDL_AtomicUnlock(SDL_SpinLock *lock); 00113 00114 /* @} *//* SDL AtomicLock */ 00115 00116 00117 /** 00118 * The compiler barrier prevents the compiler from reordering 00119 * reads and writes to globally visible variables across the call. 00120 */ 00121 #if defined(_MSC_VER) && (_MSC_VER > 1200) 00122 void _ReadWriteBarrier(void); 00123 #pragma intrinsic(_ReadWriteBarrier) 00124 #define SDL_CompilerBarrier() _ReadWriteBarrier() 00125 #elif defined(__GNUC__) 00126 #define SDL_CompilerBarrier() __asm__ __volatile__ ("" : : : "memory") 00127 #else 00128 #define SDL_CompilerBarrier() \ 00129 { SDL_SpinLock _tmp = 0; SDL_AtomicLock(&_tmp); SDL_AtomicUnlock(&_tmp); } 00130 #endif 00131 00132 /** 00133 * Memory barriers are designed to prevent reads and writes from being 00134 * reordered by the compiler and being seen out of order on multi-core CPUs. 00135 * 00136 * A typical pattern would be for thread A to write some data and a flag, 00137 * and for thread B to read the flag and get the data. In this case you 00138 * would insert a release barrier between writing the data and the flag, 00139 * guaranteeing that the data write completes no later than the flag is 00140 * written, and you would insert an acquire barrier between reading the 00141 * flag and reading the data, to ensure that all the reads associated 00142 * with the flag have completed. 00143 * 00144 * In this pattern you should always see a release barrier paired with 00145 * an acquire barrier and you should gate the data reads/writes with a 00146 * single flag variable. 00147 * 00148 * For more information on these semantics, take a look at the blog post: 00149 * http://preshing.com/20120913/acquire-and-release-semantics 00150 */ 00151 #if defined(__GNUC__) && (defined(__powerpc__) || defined(__ppc__)) 00152 #define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("lwsync" : : : "memory") 00153 #define SDL_MemoryBarrierAcquire() __asm__ __volatile__ ("lwsync" : : : "memory") 00154 #elif defined(__GNUC__) && defined(__arm__) 00155 #if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) 00156 #define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("dmb ish" : : : "memory") 00157 #define SDL_MemoryBarrierAcquire() __asm__ __volatile__ ("dmb ish" : : : "memory") 00158 #elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6T2__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) 00159 #ifdef __thumb__ 00160 /* The mcr instruction isn't available in thumb mode, use real functions */ 00161 extern DECLSPEC void SDLCALL SDL_MemoryBarrierRelease(); 00162 extern DECLSPEC void SDLCALL SDL_MemoryBarrierAcquire(); 00163 #else 00164 #define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" : : "r"(0) : "memory") 00165 #define SDL_MemoryBarrierAcquire() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" : : "r"(0) : "memory") 00166 #endif /* __thumb__ */ 00167 #else 00168 #define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("" : : : "memory") 00169 #define SDL_MemoryBarrierAcquire() __asm__ __volatile__ ("" : : : "memory") 00170 #endif /* __GNUC__ && __arm__ */ 00171 #else 00172 /* This is correct for the x86 and x64 CPUs, and we'll expand this over time. */ 00173 #define SDL_MemoryBarrierRelease() SDL_CompilerBarrier() 00174 #define SDL_MemoryBarrierAcquire() SDL_CompilerBarrier() 00175 #endif 00176 00177 /** 00178 * \brief A type representing an atomic integer value. It is a struct 00179 * so people don't accidentally use numeric operations on it. 00180 */ 00181 typedef struct { int value; } SDL_atomic_t; 00182 00183 /** 00184 * \brief Set an atomic variable to a new value if it is currently an old value. 00185 * 00186 * \return SDL_TRUE if the atomic variable was set, SDL_FALSE otherwise. 00187 * 00188 * \note If you don't know what this function is for, you shouldn't use it! 00189 */ 00190 extern DECLSPEC SDL_bool SDLCALL SDL_AtomicCAS(SDL_atomic_t *a, int oldval, int newval); 00191 00192 /** 00193 * \brief Set an atomic variable to a value. 00194 * 00195 * \return The previous value of the atomic variable. 00196 */ 00197 extern DECLSPEC int SDLCALL SDL_AtomicSet(SDL_atomic_t *a, int v); 00198 00199 /** 00200 * \brief Get the value of an atomic variable 00201 */ 00202 extern DECLSPEC int SDLCALL SDL_AtomicGet(SDL_atomic_t *a); 00203 00204 /** 00205 * \brief Add to an atomic variable. 00206 * 00207 * \return The previous value of the atomic variable. 00208 * 00209 * \note This same style can be used for any number operation 00210 */ 00211 extern DECLSPEC int SDLCALL SDL_AtomicAdd(SDL_atomic_t *a, int v); 00212 00213 /** 00214 * \brief Increment an atomic variable used as a reference count. 00215 */ 00216 #ifndef SDL_AtomicIncRef 00217 #define SDL_AtomicIncRef(a) SDL_AtomicAdd(a, 1) 00218 #endif 00219 00220 /** 00221 * \brief Decrement an atomic variable used as a reference count. 00222 * 00223 * \return SDL_TRUE if the variable reached zero after decrementing, 00224 * SDL_FALSE otherwise 00225 */ 00226 #ifndef SDL_AtomicDecRef 00227 #define SDL_AtomicDecRef(a) (SDL_AtomicAdd(a, -1) == 1) 00228 #endif 00229 00230 /** 00231 * \brief Set a pointer to a new value if it is currently an old value. 00232 * 00233 * \return SDL_TRUE if the pointer was set, SDL_FALSE otherwise. 00234 * 00235 * \note If you don't know what this function is for, you shouldn't use it! 00236 */ 00237 extern DECLSPEC SDL_bool SDLCALL SDL_AtomicCASPtr(void **a, void *oldval, void *newval); 00238 00239 /** 00240 * \brief Set a pointer to a value atomically. 00241 * 00242 * \return The previous value of the pointer. 00243 */ 00244 extern DECLSPEC void* SDLCALL SDL_AtomicSetPtr(void **a, void* v); 00245 00246 /** 00247 * \brief Get the value of a pointer atomically. 00248 */ 00249 extern DECLSPEC void* SDLCALL SDL_AtomicGetPtr(void **a); 00250 00251 /* Ends C function definitions when using C++ */ 00252 #ifdef __cplusplus 00253 } 00254 #endif 00255 00256 #include "close_code.h" 00257 00258 #endif /* _SDL_atomic_h_ */ 00259 00260 /* vi: set ts=4 sw=4 expandtab: */
Generated on Tue Jul 12 2022 13:56:23 by 1.7.2