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

Latest commit

 

History

History
319 lines (276 loc) · 9.07 KB

SDL_atomic.h

File metadata and controls

319 lines (276 loc) · 9.07 KB
 
1
2
/*
SDL - Simple DirectMedia Layer
Feb 12, 2011
Feb 12, 2011
3
Copyright (C) 1997-2011 Sam Lantinga
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
/**
Jan 15, 2011
Jan 15, 2011
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
* \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
41
* ^^^^^^^^^^^^^^^^^^^^^^^^^^^
Jan 15, 2011
Jan 15, 2011
42
*
Jan 26, 2011
Jan 26, 2011
43
44
45
46
* 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
47
48
49
* There's also lots of good information here:
* http://www.1024cores.net/home/lock-free-algorithms
*
Jan 26, 2011
Jan 26, 2011
50
* These operations may or may not actually be implemented using
Jan 15, 2011
Jan 15, 2011
51
52
53
54
55
56
* 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.
57
58
59
60
61
62
63
64
65
66
*/
#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
67
68
/* 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
69
#if defined(_MSC_VER) && (_MSC_VER >= 1500) && !defined(_WIN32_WCE)
Jan 22, 2011
Jan 22, 2011
70
#include <intrin.h>
Jan 26, 2011
Jan 26, 2011
71
#define HAVE_MSC_ATOMICS 1
Jan 22, 2011
Jan 22, 2011
72
73
#endif
74
75
76
77
78
79
80
/* 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
81
/**
Jan 15, 2011
Jan 15, 2011
82
83
84
85
86
87
88
89
90
91
92
93
94
* \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
95
*/
Oct 19, 2009
Oct 19, 2009
96
/*@{*/
Sep 17, 2009
Sep 17, 2009
97
Jan 15, 2011
Jan 15, 2011
98
99
100
101
102
103
104
105
106
107
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);
108
Jun 24, 2009
Jun 24, 2009
109
/**
Jan 15, 2011
Jan 15, 2011
110
111
112
* \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
113
*/
Sep 17, 2009
Sep 17, 2009
114
extern DECLSPEC void SDLCALL SDL_AtomicLock(SDL_SpinLock *lock);
Aug 11, 2009
Aug 11, 2009
115
Jun 24, 2009
Jun 24, 2009
116
/**
Jan 15, 2011
Jan 15, 2011
117
* \brief Unlock a spin lock by setting it to 0. Always returns immediately
Jun 24, 2009
Jun 24, 2009
118
*
Jan 15, 2011
Jan 15, 2011
119
* \param lock Points to the lock.
Jun 24, 2009
Jun 24, 2009
120
*/
Sep 17, 2009
Sep 17, 2009
121
122
extern DECLSPEC void SDLCALL SDL_AtomicUnlock(SDL_SpinLock *lock);
Oct 19, 2009
Oct 19, 2009
123
/*@}*//*SDL AtomicLock*/
Sep 17, 2009
Sep 17, 2009
124
Jan 26, 2011
Jan 26, 2011
125
Feb 1, 2011
Feb 1, 2011
126
127
128
129
/**
* The compiler barrier prevents the compiler from reordering
* reads and writes to globally visible variables across the call.
*/
Jan 26, 2011
Jan 26, 2011
130
131
132
133
#ifdef _MSC_VER
void _ReadWriteBarrier(void);
#pragma intrinsic(_ReadWriteBarrier)
#define SDL_CompilerBarrier() _ReadWriteBarrier()
Jan 26, 2011
Jan 26, 2011
134
#elif defined(__GNUC__)
Jan 26, 2011
Jan 26, 2011
135
136
137
138
139
140
#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
141
142
143
/* Platform specific optimized versions of the atomic functions,
* you can disable these by defining SDL_DISABLE_ATOMIC_INLINE
*/
Feb 8, 2011
Feb 8, 2011
144
145
146
#if SDL_ATOMIC_DISABLED
#define SDL_DISABLE_ATOMIC_INLINE
#endif
Jan 17, 2011
Jan 17, 2011
147
148
#ifndef SDL_DISABLE_ATOMIC_INLINE
Jan 26, 2011
Jan 26, 2011
149
#ifdef HAVE_MSC_ATOMICS
Jan 16, 2011
Jan 16, 2011
150
Jan 17, 2011
Jan 17, 2011
151
152
153
#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
154
#define SDL_AtomicSetPtr(a, v) _InterlockedExchangePointer((a), (v))
Jan 17, 2011
Jan 17, 2011
155
156
157
158
159
#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
160
Jan 26, 2011
Jan 26, 2011
161
#elif defined(__MACOSX__)
Jan 16, 2011
Jan 16, 2011
162
163
#include <libkern/OSAtomic.h>
Jan 26, 2011
Jan 26, 2011
164
#define SDL_AtomicCAS(a, oldval, newval) OSAtomicCompareAndSwap32Barrier((oldval), (newval), &(a)->value)
Jan 16, 2011
Jan 16, 2011
165
166
167
168
169
170
#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
171
#elif defined(HAVE_GCC_ATOMICS)
Jan 16, 2011
Jan 16, 2011
172
173
174
#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
175
#define SDL_AtomicSetPtr(a, v) __sync_lock_test_and_set(a, v)
Jan 16, 2011
Jan 16, 2011
176
177
178
179
#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
180
Jan 17, 2011
Jan 17, 2011
181
182
183
#endif /* !SDL_DISABLE_ATOMIC_INLINE */
Oct 19, 2009
Oct 19, 2009
184
/**
Jan 15, 2011
Jan 15, 2011
185
186
* \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
187
*/
Jan 15, 2011
Jan 15, 2011
188
189
190
#ifndef SDL_atomic_t_defined
typedef struct { int value; } SDL_atomic_t;
#endif
Aug 11, 2009
Aug 11, 2009
191
Jan 26, 2011
Jan 26, 2011
192
193
194
195
196
197
198
199
200
201
202
203
/**
* \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
204
/**
Jan 15, 2011
Jan 15, 2011
205
206
207
* \brief Set an atomic variable to a value.
*
* \return The previous value of the atomic variable.
Jun 24, 2009
Jun 24, 2009
208
*/
Jan 15, 2011
Jan 15, 2011
209
#ifndef SDL_AtomicSet
Jan 26, 2011
Jan 26, 2011
210
211
212
213
214
215
216
217
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
218
#endif
Aug 11, 2009
Aug 11, 2009
219
Jun 24, 2009
Jun 24, 2009
220
/**
Jan 15, 2011
Jan 15, 2011
221
* \brief Get the value of an atomic variable
Jun 24, 2009
Jun 24, 2009
222
*/
Jan 15, 2011
Jan 15, 2011
223
#ifndef SDL_AtomicGet
Jan 26, 2011
Jan 26, 2011
224
225
226
227
228
229
static __inline__ int SDL_AtomicGet(SDL_atomic_t *a)
{
int value = a->value;
SDL_CompilerBarrier();
return value;
}
Jan 15, 2011
Jan 15, 2011
230
#endif
Aug 11, 2009
Aug 11, 2009
231
Jun 24, 2009
Jun 24, 2009
232
/**
Jan 26, 2011
Jan 26, 2011
233
* \brief Add to an atomic variable.
Jan 15, 2011
Jan 15, 2011
234
235
*
* \return The previous value of the atomic variable.
Jan 26, 2011
Jan 26, 2011
236
237
*
* \note This same style can be used for any number operation
Jun 24, 2009
Jun 24, 2009
238
*/
Jan 15, 2011
Jan 15, 2011
239
#ifndef SDL_AtomicAdd
Jan 26, 2011
Jan 26, 2011
240
241
242
243
244
245
246
247
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
248
#endif
Aug 11, 2009
Aug 11, 2009
249
Jun 24, 2009
Jun 24, 2009
250
/**
Jan 15, 2011
Jan 15, 2011
251
* \brief Increment an atomic variable used as a reference count.
Jun 24, 2009
Jun 24, 2009
252
*/
Jan 15, 2011
Jan 15, 2011
253
#ifndef SDL_AtomicIncRef
Jan 26, 2011
Jan 26, 2011
254
#define SDL_AtomicIncRef(a) SDL_AtomicAdd(a, 1)
Jan 15, 2011
Jan 15, 2011
255
#endif
Aug 11, 2009
Aug 11, 2009
256
Jun 24, 2009
Jun 24, 2009
257
/**
Jan 15, 2011
Jan 15, 2011
258
259
* \brief Decrement an atomic variable used as a reference count.
*
Jan 26, 2011
Jan 26, 2011
260
* \return SDL_TRUE if the variable reached zero after decrementing,
Jan 15, 2011
Jan 15, 2011
261
* SDL_FALSE otherwise
Jun 24, 2009
Jun 24, 2009
262
*/
Jan 15, 2011
Jan 15, 2011
263
#ifndef SDL_AtomicDecRef
Jan 26, 2011
Jan 26, 2011
264
#define SDL_AtomicDecRef(a) (SDL_AtomicAdd(a, -1) == 1)
Jan 15, 2011
Jan 15, 2011
265
#endif
Aug 11, 2009
Aug 11, 2009
266
Jun 24, 2009
Jun 24, 2009
267
/**
Jan 26, 2011
Jan 26, 2011
268
* \brief Set a pointer to a new value if it is currently an old value.
Jan 15, 2011
Jan 15, 2011
269
*
Jan 26, 2011
Jan 26, 2011
270
* \return SDL_TRUE if the pointer was set, SDL_FALSE otherwise.
Jan 15, 2011
Jan 15, 2011
271
272
273
*
* \note If you don't know what this function is for, you shouldn't use it!
*/
Jan 26, 2011
Jan 26, 2011
274
275
#ifndef SDL_AtomicCASPtr
#define SDL_AtomicCASPtr SDL_AtomicCASPtr_
Jan 15, 2011
Jan 15, 2011
276
#endif
Feb 1, 2011
Feb 1, 2011
277
extern DECLSPEC SDL_bool SDLCALL SDL_AtomicCASPtr_(void* *a, void *oldval, void *newval);
Aug 11, 2009
Aug 11, 2009
278
Jun 24, 2009
Jun 24, 2009
279
/**
Jan 15, 2011
Jan 15, 2011
280
* \brief Set a pointer to a value atomically.
Jan 26, 2011
Jan 26, 2011
281
282
*
* \return The previous value of the pointer.
Jun 24, 2009
Jun 24, 2009
283
*/
Jan 15, 2011
Jan 15, 2011
284
#ifndef SDL_AtomicSetPtr
Jan 26, 2011
Jan 26, 2011
285
286
287
288
289
290
291
292
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
293
#endif
Aug 11, 2009
Aug 11, 2009
294
Jun 24, 2009
Jun 24, 2009
295
/**
Jan 15, 2011
Jan 15, 2011
296
* \brief Get the value of a pointer atomically.
Jun 24, 2009
Jun 24, 2009
297
*/
Jan 15, 2011
Jan 15, 2011
298
#ifndef SDL_AtomicGetPtr
Jan 26, 2011
Jan 26, 2011
299
300
301
302
303
304
static __inline__ void* SDL_AtomicGetPtr(void* *a)
{
void* value = *a;
SDL_CompilerBarrier();
return value;
}
Jan 15, 2011
Jan 15, 2011
305
#endif
Oct 19, 2009
Oct 19, 2009
306
307
308
309
310
311
312
313
314
315
316
317
318
319
/* 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: */