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

Latest commit

 

History

History
316 lines (273 loc) · 9 KB

SDL_atomic.h

File metadata and controls

316 lines (273 loc) · 9 KB
 
1
2
/*
SDL - Simple DirectMedia Layer
Jan 24, 2010
Jan 24, 2010
3
Copyright (C) 1997-2010 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
144
145
/* Platform specific optimized versions of the atomic functions,
* you can disable these by defining SDL_DISABLE_ATOMIC_INLINE
*/
#ifndef SDL_DISABLE_ATOMIC_INLINE
Jan 26, 2011
Jan 26, 2011
146
#ifdef HAVE_MSC_ATOMICS
Jan 16, 2011
Jan 16, 2011
147
Jan 17, 2011
Jan 17, 2011
148
149
150
#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
151
#define SDL_AtomicSetPtr(a, v) _InterlockedExchangePointer((a), (v))
Jan 17, 2011
Jan 17, 2011
152
153
154
155
156
#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
157
Jan 26, 2011
Jan 26, 2011
158
#elif defined(__MACOSX__)
Jan 16, 2011
Jan 16, 2011
159
160
#include <libkern/OSAtomic.h>
Jan 26, 2011
Jan 26, 2011
161
#define SDL_AtomicCAS(a, oldval, newval) OSAtomicCompareAndSwap32Barrier((oldval), (newval), &(a)->value)
Jan 16, 2011
Jan 16, 2011
162
163
164
165
166
167
#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
168
#elif defined(HAVE_GCC_ATOMICS)
Jan 16, 2011
Jan 16, 2011
169
170
171
#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
172
#define SDL_AtomicSetPtr(a, v) __sync_lock_test_and_set(a, v)
Jan 16, 2011
Jan 16, 2011
173
174
175
176
#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
177
Jan 17, 2011
Jan 17, 2011
178
179
180
#endif /* !SDL_DISABLE_ATOMIC_INLINE */
Oct 19, 2009
Oct 19, 2009
181
/**
Jan 15, 2011
Jan 15, 2011
182
183
* \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
184
*/
Jan 15, 2011
Jan 15, 2011
185
186
187
#ifndef SDL_atomic_t_defined
typedef struct { int value; } SDL_atomic_t;
#endif
Aug 11, 2009
Aug 11, 2009
188
Jan 26, 2011
Jan 26, 2011
189
190
191
192
193
194
195
196
197
198
199
200
/**
* \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
201
/**
Jan 15, 2011
Jan 15, 2011
202
203
204
* \brief Set an atomic variable to a value.
*
* \return The previous value of the atomic variable.
Jun 24, 2009
Jun 24, 2009
205
*/
Jan 15, 2011
Jan 15, 2011
206
#ifndef SDL_AtomicSet
Jan 26, 2011
Jan 26, 2011
207
208
209
210
211
212
213
214
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
215
#endif
Aug 11, 2009
Aug 11, 2009
216
Jun 24, 2009
Jun 24, 2009
217
/**
Jan 15, 2011
Jan 15, 2011
218
* \brief Get the value of an atomic variable
Jun 24, 2009
Jun 24, 2009
219
*/
Jan 15, 2011
Jan 15, 2011
220
#ifndef SDL_AtomicGet
Jan 26, 2011
Jan 26, 2011
221
222
223
224
225
226
static __inline__ int SDL_AtomicGet(SDL_atomic_t *a)
{
int value = a->value;
SDL_CompilerBarrier();
return value;
}
Jan 15, 2011
Jan 15, 2011
227
#endif
Aug 11, 2009
Aug 11, 2009
228
Jun 24, 2009
Jun 24, 2009
229
/**
Jan 26, 2011
Jan 26, 2011
230
* \brief Add to an atomic variable.
Jan 15, 2011
Jan 15, 2011
231
232
*
* \return The previous value of the atomic variable.
Jan 26, 2011
Jan 26, 2011
233
234
*
* \note This same style can be used for any number operation
Jun 24, 2009
Jun 24, 2009
235
*/
Jan 15, 2011
Jan 15, 2011
236
#ifndef SDL_AtomicAdd
Jan 26, 2011
Jan 26, 2011
237
238
239
240
241
242
243
244
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
245
#endif
Aug 11, 2009
Aug 11, 2009
246
Jun 24, 2009
Jun 24, 2009
247
/**
Jan 15, 2011
Jan 15, 2011
248
* \brief Increment an atomic variable used as a reference count.
Jun 24, 2009
Jun 24, 2009
249
*/
Jan 15, 2011
Jan 15, 2011
250
#ifndef SDL_AtomicIncRef
Jan 26, 2011
Jan 26, 2011
251
#define SDL_AtomicIncRef(a) SDL_AtomicAdd(a, 1)
Jan 15, 2011
Jan 15, 2011
252
#endif
Aug 11, 2009
Aug 11, 2009
253
Jun 24, 2009
Jun 24, 2009
254
/**
Jan 15, 2011
Jan 15, 2011
255
256
* \brief Decrement an atomic variable used as a reference count.
*
Jan 26, 2011
Jan 26, 2011
257
* \return SDL_TRUE if the variable reached zero after decrementing,
Jan 15, 2011
Jan 15, 2011
258
* SDL_FALSE otherwise
Jun 24, 2009
Jun 24, 2009
259
*/
Jan 15, 2011
Jan 15, 2011
260
#ifndef SDL_AtomicDecRef
Jan 26, 2011
Jan 26, 2011
261
#define SDL_AtomicDecRef(a) (SDL_AtomicAdd(a, -1) == 1)
Jan 15, 2011
Jan 15, 2011
262
#endif
Aug 11, 2009
Aug 11, 2009
263
Jun 24, 2009
Jun 24, 2009
264
/**
Jan 26, 2011
Jan 26, 2011
265
* \brief Set a pointer to a new value if it is currently an old value.
Jan 15, 2011
Jan 15, 2011
266
*
Jan 26, 2011
Jan 26, 2011
267
* \return SDL_TRUE if the pointer was set, SDL_FALSE otherwise.
Jan 15, 2011
Jan 15, 2011
268
269
270
*
* \note If you don't know what this function is for, you shouldn't use it!
*/
Jan 26, 2011
Jan 26, 2011
271
272
#ifndef SDL_AtomicCASPtr
#define SDL_AtomicCASPtr SDL_AtomicCASPtr_
Jan 15, 2011
Jan 15, 2011
273
#endif
Jan 26, 2011
Jan 26, 2011
274
extern DECLSPEC SDL_bool SDLCALL SDL_AtomicCASPtr_(void **a, void *oldval, void *newval);
Aug 11, 2009
Aug 11, 2009
275
Jun 24, 2009
Jun 24, 2009
276
/**
Jan 15, 2011
Jan 15, 2011
277
* \brief Set a pointer to a value atomically.
Jan 26, 2011
Jan 26, 2011
278
279
*
* \return The previous value of the pointer.
Jun 24, 2009
Jun 24, 2009
280
*/
Jan 15, 2011
Jan 15, 2011
281
#ifndef SDL_AtomicSetPtr
Jan 26, 2011
Jan 26, 2011
282
283
284
285
286
287
288
289
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
290
#endif
Aug 11, 2009
Aug 11, 2009
291
Jun 24, 2009
Jun 24, 2009
292
/**
Jan 15, 2011
Jan 15, 2011
293
* \brief Get the value of a pointer atomically.
Jun 24, 2009
Jun 24, 2009
294
*/
Jan 15, 2011
Jan 15, 2011
295
#ifndef SDL_AtomicGetPtr
Jan 26, 2011
Jan 26, 2011
296
297
298
299
300
301
static __inline__ void* SDL_AtomicGetPtr(void* *a)
{
void* value = *a;
SDL_CompilerBarrier();
return value;
}
Jan 15, 2011
Jan 15, 2011
302
#endif
Oct 19, 2009
Oct 19, 2009
303
304
305
306
307
308
309
310
311
312
313
314
315
316
/* 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: */