Skip to content
This repository has been archived by the owner on Feb 11, 2021. It is now read-only.

Latest commit

 

History

History
318 lines (276 loc) · 9.13 KB

SDL_atomic.h

File metadata and controls

318 lines (276 loc) · 9.13 KB
 
Apr 8, 2011
Apr 8, 2011
2
3
Simple DirectMedia Layer
Copyright (C) 1997-2011 Sam Lantinga <slouken@libsdl.org>
Apr 8, 2011
Apr 8, 2011
5
6
7
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Apr 8, 2011
Apr 8, 2011
9
10
11
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
Apr 8, 2011
Apr 8, 2011
13
14
15
16
17
18
19
20
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
21
22
/**
Jan 15, 2011
Jan 15, 2011
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
* \file SDL_atomic.h
*
* Atomic operations.
*
* IMPORTANT:
* If you are not an expert in concurrent lockless programming, you should
* only be using the atomic lock and reference counting functions in this
* file. In all other cases you should be protecting your data structures
* with full mutexes.
*
* The list of "safe" functions to use are:
* SDL_AtomicLock()
* SDL_AtomicUnlock()
* SDL_AtomicIncRef()
* SDL_AtomicDecRef()
*
* Seriously, here be dragons!
Jan 26, 2011
Jan 26, 2011
40
* ^^^^^^^^^^^^^^^^^^^^^^^^^^^
Jan 15, 2011
Jan 15, 2011
41
*
Jan 26, 2011
Jan 26, 2011
42
43
44
45
* You can find out a little more about lockless programming and the
* subtle issues that can arise here:
* http://msdn.microsoft.com/en-us/library/ee418650%28v=vs.85%29.aspx
*
Jan 26, 2011
Jan 26, 2011
46
47
48
* There's also lots of good information here:
* http://www.1024cores.net/home/lock-free-algorithms
*
Jan 26, 2011
Jan 26, 2011
49
* These operations may or may not actually be implemented using
Jan 15, 2011
Jan 15, 2011
50
51
52
53
54
55
* processor specific atomic operations. When possible they are
* implemented as true processor specific atomic operations. When that
* is not possible the are implemented using locks that *do* use the
* available atomic operations.
*
* All of the atomic operations that modify memory are full memory barriers.
56
57
58
59
60
61
62
63
64
65
*/
#ifndef _SDL_atomic_h_
#define _SDL_atomic_h_
#include "SDL_stdinc.h"
#include "SDL_platform.h"
#include "begin_code.h"
Jan 22, 2011
Jan 22, 2011
66
67
/* Need to do this here because intrin.h has C++ code in it */
/* Visual Studio 2005 has a bug where intrin.h conflicts with winnt.h */
Jan 24, 2011
Jan 24, 2011
68
#if defined(_MSC_VER) && (_MSC_VER >= 1500) && !defined(_WIN32_WCE)
Jan 22, 2011
Jan 22, 2011
69
#include <intrin.h>
Jan 26, 2011
Jan 26, 2011
70
#define HAVE_MSC_ATOMICS 1
Jan 22, 2011
Jan 22, 2011
71
72
#endif
73
74
75
76
77
78
79
/* Set up for C function definitions, even when using C++ */
#ifdef __cplusplus
/* *INDENT-OFF* */
extern "C" {
/* *INDENT-ON* */
#endif
Sep 17, 2009
Sep 17, 2009
80
/**
Jan 15, 2011
Jan 15, 2011
81
82
83
84
85
86
87
88
89
90
91
92
93
* \name SDL AtomicLock
*
* The atomic locks are efficient spinlocks using CPU instructions,
* but are vulnerable to starvation and can spin forever if a thread
* holding a lock has been terminated. For this reason you should
* minimize the code executed inside an atomic lock and never do
* expensive things like API or system calls while holding them.
*
* The atomic locks are not safe to lock recursively.
*
* Porting Note:
* The spin lock functions and type are required and can not be
* emulated because they are used in the atomic emulation code.
Sep 17, 2009
Sep 17, 2009
94
*/
Oct 19, 2009
Oct 19, 2009
95
/*@{*/
Sep 17, 2009
Sep 17, 2009
96
Jan 15, 2011
Jan 15, 2011
97
98
99
100
101
102
103
104
105
106
typedef int SDL_SpinLock;
/**
* \brief Try to lock a spin lock by setting it to a non-zero value.
*
* \param lock Points to the lock.
*
* \return SDL_TRUE if the lock succeeded, SDL_FALSE if the lock is already held.
*/
extern DECLSPEC SDL_bool SDLCALL SDL_AtomicTryLock(SDL_SpinLock *lock);
107
Jun 24, 2009
Jun 24, 2009
108
/**
Jan 15, 2011
Jan 15, 2011
109
110
111
* \brief Lock a spin lock by setting it to a non-zero value.
*
* \param lock Points to the lock.
Jun 24, 2009
Jun 24, 2009
112
*/
Sep 17, 2009
Sep 17, 2009
113
extern DECLSPEC void SDLCALL SDL_AtomicLock(SDL_SpinLock *lock);
Aug 11, 2009
Aug 11, 2009
114
Jun 24, 2009
Jun 24, 2009
115
/**
Jan 15, 2011
Jan 15, 2011
116
* \brief Unlock a spin lock by setting it to 0. Always returns immediately
Jun 24, 2009
Jun 24, 2009
117
*
Jan 15, 2011
Jan 15, 2011
118
* \param lock Points to the lock.
Jun 24, 2009
Jun 24, 2009
119
*/
Sep 17, 2009
Sep 17, 2009
120
121
extern DECLSPEC void SDLCALL SDL_AtomicUnlock(SDL_SpinLock *lock);
Oct 19, 2009
Oct 19, 2009
122
/*@}*//*SDL AtomicLock*/
Sep 17, 2009
Sep 17, 2009
123
Jan 26, 2011
Jan 26, 2011
124
Feb 1, 2011
Feb 1, 2011
125
126
127
128
/**
* The compiler barrier prevents the compiler from reordering
* reads and writes to globally visible variables across the call.
*/
Jan 26, 2011
Jan 26, 2011
129
130
131
132
#ifdef _MSC_VER
void _ReadWriteBarrier(void);
#pragma intrinsic(_ReadWriteBarrier)
#define SDL_CompilerBarrier() _ReadWriteBarrier()
Jan 26, 2011
Jan 26, 2011
133
#elif defined(__GNUC__)
Jan 26, 2011
Jan 26, 2011
134
135
136
137
138
139
#define SDL_CompilerBarrier() __asm__ __volatile__ ("" : : : "memory")
#else
#define SDL_CompilerBarrier() \
({ SDL_SpinLock _tmp = 0; SDL_AtomicLock(&_tmp); SDL_AtomicUnlock(&_tmp); })
#endif
Jan 17, 2011
Jan 17, 2011
140
141
142
/* Platform specific optimized versions of the atomic functions,
* you can disable these by defining SDL_DISABLE_ATOMIC_INLINE
*/
Feb 8, 2011
Feb 8, 2011
143
144
145
#if SDL_ATOMIC_DISABLED
#define SDL_DISABLE_ATOMIC_INLINE
#endif
Jan 17, 2011
Jan 17, 2011
146
147
#ifndef SDL_DISABLE_ATOMIC_INLINE
Jan 26, 2011
Jan 26, 2011
148
#ifdef HAVE_MSC_ATOMICS
Jan 16, 2011
Jan 16, 2011
149
Jan 17, 2011
Jan 17, 2011
150
151
152
#define SDL_AtomicSet(a, v) _InterlockedExchange((long*)&(a)->value, (v))
#define SDL_AtomicAdd(a, v) _InterlockedExchangeAdd((long*)&(a)->value, (v))
#define SDL_AtomicCAS(a, oldval, newval) (_InterlockedCompareExchange((long*)&(a)->value, (newval), (oldval)) == (oldval))
Jan 26, 2011
Jan 26, 2011
153
#define SDL_AtomicSetPtr(a, v) _InterlockedExchangePointer((a), (v))
Jan 17, 2011
Jan 17, 2011
154
155
156
157
158
#if _M_IX86
#define SDL_AtomicCASPtr(a, oldval, newval) (_InterlockedCompareExchange((long*)(a), (long)(newval), (long)(oldval)) == (long)(oldval))
#else
#define SDL_AtomicCASPtr(a, oldval, newval) (_InterlockedCompareExchangePointer((a), (newval), (oldval)) == (oldval))
#endif
Jan 16, 2011
Jan 16, 2011
159
Jan 26, 2011
Jan 26, 2011
160
#elif defined(__MACOSX__)
Jan 16, 2011
Jan 16, 2011
161
162
#include <libkern/OSAtomic.h>
Jan 26, 2011
Jan 26, 2011
163
#define SDL_AtomicCAS(a, oldval, newval) OSAtomicCompareAndSwap32Barrier((oldval), (newval), &(a)->value)
Jan 16, 2011
Jan 16, 2011
164
165
166
167
168
169
#if SIZEOF_VOIDP == 4
#define SDL_AtomicCASPtr(a, oldval, newval) OSAtomicCompareAndSwap32Barrier((int32_t)(oldval), (int32_t)(newval), (int32_t*)(a))
#elif SIZEOF_VOIDP == 8
#define SDL_AtomicCASPtr(a, oldval, newval) OSAtomicCompareAndSwap64Barrier((int64_t)(oldval), (int64_t)(newval), (int64_t*)(a))
#endif
Jan 26, 2011
Jan 26, 2011
170
#elif defined(HAVE_GCC_ATOMICS)
Jan 16, 2011
Jan 16, 2011
171
172
173
#define SDL_AtomicSet(a, v) __sync_lock_test_and_set(&(a)->value, v)
#define SDL_AtomicAdd(a, v) __sync_fetch_and_add(&(a)->value, v)
Jan 26, 2011
Jan 26, 2011
174
#define SDL_AtomicSetPtr(a, v) __sync_lock_test_and_set(a, v)
Jan 16, 2011
Jan 16, 2011
175
176
177
178
#define SDL_AtomicCAS(a, oldval, newval) __sync_bool_compare_and_swap(&(a)->value, oldval, newval)
#define SDL_AtomicCASPtr(a, oldval, newval) __sync_bool_compare_and_swap(a, oldval, newval)
#endif
Oct 19, 2009
Oct 19, 2009
179
Jan 17, 2011
Jan 17, 2011
180
181
182
#endif /* !SDL_DISABLE_ATOMIC_INLINE */
Oct 19, 2009
Oct 19, 2009
183
/**
Jan 15, 2011
Jan 15, 2011
184
185
* \brief A type representing an atomic integer value. It is a struct
* so people don't accidentally use numeric operations on it.
Jun 24, 2009
Jun 24, 2009
186
*/
Jan 15, 2011
Jan 15, 2011
187
188
189
#ifndef SDL_atomic_t_defined
typedef struct { int value; } SDL_atomic_t;
#endif
Aug 11, 2009
Aug 11, 2009
190
Jan 26, 2011
Jan 26, 2011
191
192
193
194
195
196
197
198
199
200
201
202
/**
* \brief Set an atomic variable to a new value if it is currently an old value.
*
* \return SDL_TRUE if the atomic variable was set, SDL_FALSE otherwise.
*
* \note If you don't know what this function is for, you shouldn't use it!
*/
#ifndef SDL_AtomicCAS
#define SDL_AtomicCAS SDL_AtomicCAS_
#endif
extern DECLSPEC SDL_bool SDLCALL SDL_AtomicCAS_(SDL_atomic_t *a, int oldval, int newval);
Jun 24, 2009
Jun 24, 2009
203
/**
Jan 15, 2011
Jan 15, 2011
204
205
206
* \brief Set an atomic variable to a value.
*
* \return The previous value of the atomic variable.
Jun 24, 2009
Jun 24, 2009
207
*/
Jan 15, 2011
Jan 15, 2011
208
#ifndef SDL_AtomicSet
Jan 26, 2011
Jan 26, 2011
209
210
211
212
213
214
215
216
static __inline__ int SDL_AtomicSet(SDL_atomic_t *a, int v)
{
int value;
do {
value = a->value;
} while (!SDL_AtomicCAS(a, value, v));
return value;
}
Jan 15, 2011
Jan 15, 2011
217
#endif
Aug 11, 2009
Aug 11, 2009
218
Jun 24, 2009
Jun 24, 2009
219
/**
Jan 15, 2011
Jan 15, 2011
220
* \brief Get the value of an atomic variable
Jun 24, 2009
Jun 24, 2009
221
*/
Jan 15, 2011
Jan 15, 2011
222
#ifndef SDL_AtomicGet
Jan 26, 2011
Jan 26, 2011
223
224
225
226
227
228
static __inline__ int SDL_AtomicGet(SDL_atomic_t *a)
{
int value = a->value;
SDL_CompilerBarrier();
return value;
}
Jan 15, 2011
Jan 15, 2011
229
#endif
Aug 11, 2009
Aug 11, 2009
230
Jun 24, 2009
Jun 24, 2009
231
/**
Jan 26, 2011
Jan 26, 2011
232
* \brief Add to an atomic variable.
Jan 15, 2011
Jan 15, 2011
233
234
*
* \return The previous value of the atomic variable.
Jan 26, 2011
Jan 26, 2011
235
236
*
* \note This same style can be used for any number operation
Jun 24, 2009
Jun 24, 2009
237
*/
Jan 15, 2011
Jan 15, 2011
238
#ifndef SDL_AtomicAdd
Jan 26, 2011
Jan 26, 2011
239
240
241
242
243
244
245
246
static __inline__ int SDL_AtomicAdd(SDL_atomic_t *a, int v)
{
int value;
do {
value = a->value;
} while (!SDL_AtomicCAS(a, value, (value + v)));
return value;
}
Jan 15, 2011
Jan 15, 2011
247
#endif
Aug 11, 2009
Aug 11, 2009
248
Jun 24, 2009
Jun 24, 2009
249
/**
Jan 15, 2011
Jan 15, 2011
250
* \brief Increment an atomic variable used as a reference count.
Jun 24, 2009
Jun 24, 2009
251
*/
Jan 15, 2011
Jan 15, 2011
252
#ifndef SDL_AtomicIncRef
Jan 26, 2011
Jan 26, 2011
253
#define SDL_AtomicIncRef(a) SDL_AtomicAdd(a, 1)
Jan 15, 2011
Jan 15, 2011
254
#endif
Aug 11, 2009
Aug 11, 2009
255
Jun 24, 2009
Jun 24, 2009
256
/**
Jan 15, 2011
Jan 15, 2011
257
258
* \brief Decrement an atomic variable used as a reference count.
*
Jan 26, 2011
Jan 26, 2011
259
* \return SDL_TRUE if the variable reached zero after decrementing,
Jan 15, 2011
Jan 15, 2011
260
* SDL_FALSE otherwise
Jun 24, 2009
Jun 24, 2009
261
*/
Jan 15, 2011
Jan 15, 2011
262
#ifndef SDL_AtomicDecRef
Jan 26, 2011
Jan 26, 2011
263
#define SDL_AtomicDecRef(a) (SDL_AtomicAdd(a, -1) == 1)
Jan 15, 2011
Jan 15, 2011
264
#endif
Aug 11, 2009
Aug 11, 2009
265
Jun 24, 2009
Jun 24, 2009
266
/**
Jan 26, 2011
Jan 26, 2011
267
* \brief Set a pointer to a new value if it is currently an old value.
Jan 15, 2011
Jan 15, 2011
268
*
Jan 26, 2011
Jan 26, 2011
269
* \return SDL_TRUE if the pointer was set, SDL_FALSE otherwise.
Jan 15, 2011
Jan 15, 2011
270
271
272
*
* \note If you don't know what this function is for, you shouldn't use it!
*/
Jan 26, 2011
Jan 26, 2011
273
274
#ifndef SDL_AtomicCASPtr
#define SDL_AtomicCASPtr SDL_AtomicCASPtr_
Jan 15, 2011
Jan 15, 2011
275
#endif
Feb 1, 2011
Feb 1, 2011
276
extern DECLSPEC SDL_bool SDLCALL SDL_AtomicCASPtr_(void* *a, void *oldval, void *newval);
Aug 11, 2009
Aug 11, 2009
277
Jun 24, 2009
Jun 24, 2009
278
/**
Jan 15, 2011
Jan 15, 2011
279
* \brief Set a pointer to a value atomically.
Jan 26, 2011
Jan 26, 2011
280
281
*
* \return The previous value of the pointer.
Jun 24, 2009
Jun 24, 2009
282
*/
Jan 15, 2011
Jan 15, 2011
283
#ifndef SDL_AtomicSetPtr
Jan 26, 2011
Jan 26, 2011
284
285
286
287
288
289
290
291
static __inline__ void* SDL_AtomicSetPtr(void* *a, void* v)
{
void* value;
do {
value = *a;
} while (!SDL_AtomicCASPtr(a, value, v));
return value;
}
Jan 15, 2011
Jan 15, 2011
292
#endif
Aug 11, 2009
Aug 11, 2009
293
Jun 24, 2009
Jun 24, 2009
294
/**
Jan 15, 2011
Jan 15, 2011
295
* \brief Get the value of a pointer atomically.
Jun 24, 2009
Jun 24, 2009
296
*/
Jan 15, 2011
Jan 15, 2011
297
#ifndef SDL_AtomicGetPtr
Jan 26, 2011
Jan 26, 2011
298
299
300
301
302
303
static __inline__ void* SDL_AtomicGetPtr(void* *a)
{
void* value = *a;
SDL_CompilerBarrier();
return value;
}
Jan 15, 2011
Jan 15, 2011
304
#endif
Oct 19, 2009
Oct 19, 2009
305
306
307
308
309
310
311
312
313
314
315
316
317
318
/* Ends C function definitions when using C++ */
#ifdef __cplusplus
/* *INDENT-OFF* */
}
/* *INDENT-ON* */
#endif
#include "close_code.h"
#endif /* _SDL_atomic_h_ */
/* vi: set ts=4 sw=4 expandtab: */