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

Latest commit

 

History

History
311 lines (269 loc) · 9.19 KB

SDL_atomic.h

File metadata and controls

311 lines (269 loc) · 9.19 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
47
* 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
*
* These operations may or may not actually be implemented using
Jan 15, 2011
Jan 15, 2011
48
49
50
51
52
53
* 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.
54
55
56
57
58
59
60
61
62
63
*/
#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
64
65
/* 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
66
#if defined(_MSC_VER) && (_MSC_VER >= 1500) && !defined(_WIN32_WCE)
Jan 22, 2011
Jan 22, 2011
67
68
69
70
#include <intrin.h>
#define HAVE_MSC_ATOMICS
#endif
71
72
73
74
75
76
77
/* 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
78
/**
Jan 15, 2011
Jan 15, 2011
79
80
81
82
83
84
85
86
87
88
89
90
91
* \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
92
*/
Oct 19, 2009
Oct 19, 2009
93
/*@{*/
Sep 17, 2009
Sep 17, 2009
94
Jan 15, 2011
Jan 15, 2011
95
96
97
98
99
100
101
102
103
104
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);
105
Jun 24, 2009
Jun 24, 2009
106
/**
Jan 15, 2011
Jan 15, 2011
107
108
109
* \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
110
*/
Sep 17, 2009
Sep 17, 2009
111
extern DECLSPEC void SDLCALL SDL_AtomicLock(SDL_SpinLock *lock);
Aug 11, 2009
Aug 11, 2009
112
Jun 24, 2009
Jun 24, 2009
113
/**
Jan 15, 2011
Jan 15, 2011
114
* \brief Unlock a spin lock by setting it to 0. Always returns immediately
Jun 24, 2009
Jun 24, 2009
115
*
Jan 15, 2011
Jan 15, 2011
116
* \param lock Points to the lock.
Jun 24, 2009
Jun 24, 2009
117
*/
Sep 17, 2009
Sep 17, 2009
118
119
extern DECLSPEC void SDLCALL SDL_AtomicUnlock(SDL_SpinLock *lock);
Oct 19, 2009
Oct 19, 2009
120
/*@}*//*SDL AtomicLock*/
Sep 17, 2009
Sep 17, 2009
121
Jan 26, 2011
Jan 26, 2011
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/* The compiler barrier prevents the compiler from reordering
reads and writes to globally visible variables across the call.
*/
#ifdef _MSC_VER
void _ReadWriteBarrier(void);
#pragma intrinsic(_ReadWriteBarrier)
#define SDL_CompilerBarrier() _ReadWriteBarrier()
#elif __GNUC__
#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
137
138
139
140
141
/* 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
142
#if HAVE_MSC_ATOMICS
Jan 16, 2011
Jan 16, 2011
143
Jan 17, 2011
Jan 17, 2011
144
145
146
#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
147
#define SDL_AtomicSetPtr(a, v) _InterlockedExchangePointer((a), (v))
Jan 17, 2011
Jan 17, 2011
148
149
150
151
152
#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
153
Jan 26, 2011
Jan 26, 2011
154
#elif __MACOSX__
Jan 16, 2011
Jan 16, 2011
155
156
#include <libkern/OSAtomic.h>
Jan 26, 2011
Jan 26, 2011
157
#define SDL_AtomicCAS(a, oldval, newval) OSAtomicCompareAndSwap32Barrier((oldval), (newval), &(a)->value)
Jan 16, 2011
Jan 16, 2011
158
159
160
161
162
163
#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
164
#elif HAVE_GCC_ATOMICS
Jan 16, 2011
Jan 16, 2011
165
166
167
#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
168
#define SDL_AtomicSetPtr(a, v) __sync_lock_test_and_set(a, v)
Jan 16, 2011
Jan 16, 2011
169
170
171
172
#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
173
Jan 17, 2011
Jan 17, 2011
174
175
176
#endif /* !SDL_DISABLE_ATOMIC_INLINE */
Oct 19, 2009
Oct 19, 2009
177
/**
Jan 15, 2011
Jan 15, 2011
178
179
* \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
180
*/
Jan 15, 2011
Jan 15, 2011
181
182
183
#ifndef SDL_atomic_t_defined
typedef struct { int value; } SDL_atomic_t;
#endif
Aug 11, 2009
Aug 11, 2009
184
Jun 24, 2009
Jun 24, 2009
185
/**
Jan 15, 2011
Jan 15, 2011
186
187
188
* \brief Set an atomic variable to a value.
*
* \return The previous value of the atomic variable.
Jun 24, 2009
Jun 24, 2009
189
*/
Jan 15, 2011
Jan 15, 2011
190
#ifndef SDL_AtomicSet
Jan 26, 2011
Jan 26, 2011
191
192
193
194
195
196
197
198
#define SDL_AtomicSet(a, v) \
({ \
int _value; \
do { \
_value = (a)->value; \
} while (!SDL_AtomicCAS(a, _value, (v))); \
_value; \
})
Jan 15, 2011
Jan 15, 2011
199
#endif
Aug 11, 2009
Aug 11, 2009
200
Jun 24, 2009
Jun 24, 2009
201
/**
Jan 15, 2011
Jan 15, 2011
202
* \brief Get the value of an atomic variable
Jun 24, 2009
Jun 24, 2009
203
*/
Jan 15, 2011
Jan 15, 2011
204
#ifndef SDL_AtomicGet
Jan 26, 2011
Jan 26, 2011
205
206
207
208
209
210
#define SDL_AtomicGet(a) \
({ \
int _value = (a)->value; \
SDL_CompilerBarrier(); \
_value; \
})
Jan 15, 2011
Jan 15, 2011
211
#endif
Aug 11, 2009
Aug 11, 2009
212
Jun 24, 2009
Jun 24, 2009
213
/**
Jan 26, 2011
Jan 26, 2011
214
* \brief Add to an atomic variable.
Jan 15, 2011
Jan 15, 2011
215
216
*
* \return The previous value of the atomic variable.
Jan 26, 2011
Jan 26, 2011
217
218
*
* \note This same style can be used for any number operation
Jun 24, 2009
Jun 24, 2009
219
*/
Jan 15, 2011
Jan 15, 2011
220
#ifndef SDL_AtomicAdd
Jan 26, 2011
Jan 26, 2011
221
222
223
224
225
226
227
228
#define SDL_AtomicAdd(a, v) \
({ \
int _value; \
do { \
_value = (a)->value; \
} while (!SDL_AtomicCAS(a, _value, (_value + (v)))); \
_value; \
})
Jan 15, 2011
Jan 15, 2011
229
#endif
Aug 11, 2009
Aug 11, 2009
230
Jun 24, 2009
Jun 24, 2009
231
/**
Jan 15, 2011
Jan 15, 2011
232
* \brief Increment an atomic variable used as a reference count.
Jun 24, 2009
Jun 24, 2009
233
*/
Jan 15, 2011
Jan 15, 2011
234
#ifndef SDL_AtomicIncRef
Jan 26, 2011
Jan 26, 2011
235
#define SDL_AtomicIncRef(a) SDL_AtomicAdd(a, 1)
Jan 15, 2011
Jan 15, 2011
236
#endif
Aug 11, 2009
Aug 11, 2009
237
Jun 24, 2009
Jun 24, 2009
238
/**
Jan 15, 2011
Jan 15, 2011
239
240
* \brief Decrement an atomic variable used as a reference count.
*
Jan 26, 2011
Jan 26, 2011
241
* \return SDL_TRUE if the variable reached zero after decrementing,
Jan 15, 2011
Jan 15, 2011
242
* SDL_FALSE otherwise
Jun 24, 2009
Jun 24, 2009
243
*/
Jan 15, 2011
Jan 15, 2011
244
#ifndef SDL_AtomicDecRef
Jan 26, 2011
Jan 26, 2011
245
#define SDL_AtomicDecRef(a) (SDL_AtomicAdd(a, -1) == 1)
Jan 15, 2011
Jan 15, 2011
246
#endif
Aug 11, 2009
Aug 11, 2009
247
Jun 24, 2009
Jun 24, 2009
248
/**
Jan 15, 2011
Jan 15, 2011
249
250
* \brief Set an atomic variable to a new value if it is currently an old value.
*
Jan 16, 2011
Jan 16, 2011
251
* \return SDL_TRUE if the atomic variable was set, SDL_FALSE otherwise.
Jan 15, 2011
Jan 15, 2011
252
253
254
255
*
* \note If you don't know what this function is for, you shouldn't use it!
*/
#ifndef SDL_AtomicCAS
Jan 26, 2011
Jan 26, 2011
256
#define SDL_AtomicCAS SDL_AtomicCAS_
Jan 15, 2011
Jan 15, 2011
257
#endif
Jan 26, 2011
Jan 26, 2011
258
extern DECLSPEC SDL_bool SDLCALL SDL_AtomicCAS_(SDL_atomic_t *a, int oldval, int newval);
Aug 11, 2009
Aug 11, 2009
259
Jun 24, 2009
Jun 24, 2009
260
/**
Jan 15, 2011
Jan 15, 2011
261
* \brief Set a pointer to a value atomically.
Jan 26, 2011
Jan 26, 2011
262
263
*
* \return The previous value of the pointer.
Jun 24, 2009
Jun 24, 2009
264
*/
Jan 15, 2011
Jan 15, 2011
265
#ifndef SDL_AtomicSetPtr
Jan 26, 2011
Jan 26, 2011
266
267
268
269
270
271
272
273
#define SDL_AtomicSetPtr(a, v) \
({ \
void* _value; \
do { \
_value = *(a); \
} while (!SDL_AtomicCASPtr(a, _value, (v))); \
_value; \
})
Jan 15, 2011
Jan 15, 2011
274
#endif
Aug 11, 2009
Aug 11, 2009
275
Jun 24, 2009
Jun 24, 2009
276
/**
Jan 15, 2011
Jan 15, 2011
277
* \brief Get the value of a pointer atomically.
Jun 24, 2009
Jun 24, 2009
278
*/
Jan 15, 2011
Jan 15, 2011
279
#ifndef SDL_AtomicGetPtr
Jan 26, 2011
Jan 26, 2011
280
281
282
283
284
285
#define SDL_AtomicGetPtr(a) \
({ \
void* _value = *(a); \
SDL_CompilerBarrier(); \
_value; \
})
Jan 15, 2011
Jan 15, 2011
286
#endif
Oct 19, 2009
Oct 19, 2009
287
288
/**
Jan 15, 2011
Jan 15, 2011
289
290
* \brief Set a pointer to a new value if it is currently an old value.
*
Jan 16, 2011
Jan 16, 2011
291
* \return SDL_TRUE if the pointer was set, SDL_FALSE otherwise.
Jan 15, 2011
Jan 15, 2011
292
293
294
295
*
* \note If you don't know what this function is for, you shouldn't use it!
*/
#ifndef SDL_AtomicCASPtr
Jan 26, 2011
Jan 26, 2011
296
#define SDL_AtomicCASPtr SDL_AtomicCASPtr_
Jan 15, 2011
Jan 15, 2011
297
#endif
Jan 26, 2011
Jan 26, 2011
298
extern DECLSPEC SDL_bool SDLCALL SDL_AtomicCASPtr_(void **a, void *oldval, void *newval);
Oct 19, 2009
Oct 19, 2009
299
300
301
302
303
304
305
306
307
308
309
310
311
/* 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: */