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

Latest commit

 

History

History
469 lines (384 loc) · 8.75 KB

SDL_atomic.c

File metadata and controls

469 lines (384 loc) · 8.75 KB
 
Sep 17, 2009
Sep 17, 2009
2
SDL - Simple DirectMedia Layer
Jan 24, 2010
Jan 24, 2010
3
Copyright (C) 1997-2010 Sam Lantinga
Sep 17, 2009
Sep 17, 2009
5
6
7
8
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.
Sep 17, 2009
Sep 17, 2009
10
11
12
13
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.
Sep 17, 2009
Sep 17, 2009
15
16
17
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
Sep 17, 2009
Sep 17, 2009
19
20
21
22
Sam Lantinga
slouken@libsdl.org
Contributed by Bob Pendleton, bob@pendleton.com
Jun 29, 2009
Jun 29, 2009
25
#include "SDL_stdinc.h"
26
27
#include "SDL_atomic.h"
Sep 17, 2009
Sep 17, 2009
28
29
#include "SDL_error.h"
Jun 29, 2009
Jun 29, 2009
30
/*
Sep 17, 2009
Sep 17, 2009
31
This file provides 32, and 64 bit atomic operations. If the
Jun 29, 2009
Jun 29, 2009
32
33
operations are provided by the native hardware and operating system
they are used. If they are not then the operations are emulated
Sep 17, 2009
Sep 17, 2009
34
35
using the SDL spin lock operations. If spin lock can not be
implemented then these functions must fail.
Jun 29, 2009
Jun 29, 2009
36
37
38
*/
/*
Sep 17, 2009
Sep 17, 2009
39
DUMMY VERSION.
Jun 29, 2009
Jun 29, 2009
40
Sep 17, 2009
Sep 17, 2009
41
42
43
44
45
This version of the code assumes there is no support for atomic
operations. Therefore, every function sets the SDL error
message. Oddly enough, if you only have one thread then this
version actuallys works.
*/
Jun 29, 2009
Jun 29, 2009
46
Sep 17, 2009
Sep 17, 2009
47
48
49
50
/*
Native spinlock routines. Because this is the dummy implementation
these will always call SDL_SetError() and do nothing.
*/
Jun 29, 2009
Jun 29, 2009
51
Sep 17, 2009
Sep 17, 2009
52
53
void
SDL_AtomicLock(SDL_SpinLock *lock)
Jun 29, 2009
Jun 29, 2009
54
{
Sep 17, 2009
Sep 17, 2009
55
SDL_SetError("SDL_atomic.c: is not implemented on this platform");
Jun 29, 2009
Jun 29, 2009
56
57
}
Sep 17, 2009
Sep 17, 2009
58
59
void
SDL_AtomicUnlock(SDL_SpinLock *lock)
Jun 29, 2009
Jun 29, 2009
60
{
Sep 17, 2009
Sep 17, 2009
61
SDL_SetError("SDL_atomic.c: is not implemented on this platform");
Jun 29, 2009
Jun 29, 2009
62
63
}
Sep 17, 2009
Sep 17, 2009
64
65
66
67
68
/*
Note that platform specific versions can be built from this version
by changing the #undefs to #defines and adding platform specific
code.
*/
Jun 29, 2009
Jun 29, 2009
69
Sep 17, 2009
Sep 17, 2009
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#undef nativeTestThenSet32
#undef nativeClear32
#undef nativeFetchThenIncrement32
#undef nativeFetchThenDecrement32
#undef nativeFetchThenAdd32
#undef nativeFetchThenSubtract32
#undef nativeIncrementThenFetch32
#undef nativeDecrementThenFetch32
#undef nativeAddThenFetch32
#undef nativeSubtractThenFetch32
#undef nativeTestThenSet64
#undef nativeClear64
#undef nativeFetchThenIncrement64
#undef nativeFetchThenDecrement64
#undef nativeFetchThenAdd64
#undef nativeFetchThenSubtract64
#undef nativeIncrementThenFetch64
#undef nativeDecrementThenFetch64
#undef nativeAddThenFetch64
#undef nativeSubtractThenFetch64
Jun 29, 2009
Jun 29, 2009
91
Sep 17, 2009
Sep 17, 2009
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
/*
If any of the operations are not provided then we must emulate some
of them. That means we need a nice implementation of spin locks
that avoids the "one big lock" problem. We use a vector of spin
locks and pick which one to use based on the address of the operand
of the function.
To generate the index of the lock we first shift by 3 bits to get
rid on the zero bits that result from 32 and 64 bit allignment of
data. We then mask off all but 5 bits and use those 5 bits as an
index into the table.
Picking the lock this way insures that accesses to the same data at
the same time will go to the same lock. OTOH, accesses to different
data have only a 1/32 chance of hitting the same lock. That should
pretty much eliminate the chances of several atomic operations on
different data from waiting on the same "big lock". If it isn't
then the table of locks can be expanded to a new size so long as
Sep 25, 2009
Sep 25, 2009
110
the new size is a power of two.
Sep 17, 2009
Sep 17, 2009
111
*/
Jun 29, 2009
Jun 29, 2009
112
Sep 17, 2009
Sep 17, 2009
113
114
115
116
117
118
static SDL_SpinLock locks[32] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
};
Jun 29, 2009
Jun 29, 2009
119
Sep 17, 2009
Sep 17, 2009
120
121
static __inline__ void
privateWaitLock(volatile void *ptr)
Jun 29, 2009
Jun 29, 2009
122
{
Sep 17, 2009
Sep 17, 2009
123
124
125
126
#if SIZEOF_VOIDP == 4
Uint32 index = ((((Uint32)ptr) >> 3) & 0x1f);
#elif SIZEOF_VOIDP == 8
Uint64 index = ((((Uint64)ptr) >> 3) & 0x1f);
Jun 29, 2009
Jun 29, 2009
127
128
#endif
Sep 17, 2009
Sep 17, 2009
129
SDL_AtomicLock(&locks[index]);
Jun 29, 2009
Jun 29, 2009
130
131
}
Sep 17, 2009
Sep 17, 2009
132
133
static __inline__ void
privateUnlock(volatile void *ptr)
Jun 29, 2009
Jun 29, 2009
134
{
Sep 17, 2009
Sep 17, 2009
135
136
137
138
#if SIZEOF_VOIDP == 4
Uint32 index = ((((Uint32)ptr) >> 3) & 0x1f);
#elif SIZEOF_VOIDP == 8
Uint64 index = ((((Uint64)ptr) >> 3) & 0x1f);
Jun 29, 2009
Jun 29, 2009
139
140
#endif
Sep 17, 2009
Sep 17, 2009
141
SDL_AtomicUnlock(&locks[index]);
Jun 29, 2009
Jun 29, 2009
142
143
144
145
}
/* 32 bit atomic operations */
Aug 11, 2009
Aug 11, 2009
147
SDL_AtomicTestThenSet32(volatile Uint32 * ptr)
Jun 29, 2009
Jun 29, 2009
149
150
151
152
#ifdef nativeTestThenSet32
#else
SDL_bool result = SDL_FALSE;
Sep 17, 2009
Sep 17, 2009
153
privateWaitLock(ptr);
Jun 29, 2009
Jun 29, 2009
154
155
156
157
158
result = (*ptr == 0);
if (result)
{
*ptr = 1;
}
Sep 17, 2009
Sep 17, 2009
159
privateUnlock(ptr);
Jun 29, 2009
Jun 29, 2009
160
161
162
return result;
#endif
Aug 11, 2009
Aug 11, 2009
166
SDL_AtomicClear32(volatile Uint32 * ptr)
Jun 29, 2009
Jun 29, 2009
168
169
#ifdef nativeClear32
#else
Sep 17, 2009
Sep 17, 2009
170
privateWaitLock(ptr);
Jun 29, 2009
Jun 29, 2009
171
*ptr = 0;
Sep 17, 2009
Sep 17, 2009
172
privateUnlock(ptr);
Jun 29, 2009
Jun 29, 2009
173
174
175
return;
#endif
Aug 11, 2009
Aug 11, 2009
179
SDL_AtomicFetchThenIncrement32(volatile Uint32 * ptr)
Jun 29, 2009
Jun 29, 2009
181
182
#ifdef nativeFetchThenIncrement32
#else
Jul 2, 2009
Jul 2, 2009
183
Uint32 tmp = 0;
Jun 29, 2009
Jun 29, 2009
184
Sep 17, 2009
Sep 17, 2009
185
privateWaitLock(ptr);
Jun 29, 2009
Jun 29, 2009
186
187
tmp = *ptr;
(*ptr)+= 1;
Sep 17, 2009
Sep 17, 2009
188
privateUnlock(ptr);
Jun 29, 2009
Jun 29, 2009
189
190
191
return tmp;
#endif
Aug 11, 2009
Aug 11, 2009
195
SDL_AtomicFetchThenDecrement32(volatile Uint32 * ptr)
Jun 29, 2009
Jun 29, 2009
197
198
#ifdef nativeFetchThenDecrement32
#else
Jul 2, 2009
Jul 2, 2009
199
Uint32 tmp = 0;
Jun 29, 2009
Jun 29, 2009
200
Sep 17, 2009
Sep 17, 2009
201
privateWaitLock(ptr);
Jun 29, 2009
Jun 29, 2009
202
203
tmp = *ptr;
(*ptr) -= 1;
Sep 17, 2009
Sep 17, 2009
204
privateUnlock(ptr);
Jun 29, 2009
Jun 29, 2009
205
206
207
return tmp;
#endif
Aug 11, 2009
Aug 11, 2009
211
SDL_AtomicFetchThenAdd32(volatile Uint32 * ptr, Uint32 value)
Jun 29, 2009
Jun 29, 2009
213
214
#ifdef nativeFetchThenAdd32
#else
Jul 2, 2009
Jul 2, 2009
215
Uint32 tmp = 0;
Jun 29, 2009
Jun 29, 2009
216
Sep 17, 2009
Sep 17, 2009
217
privateWaitLock(ptr);
Jun 29, 2009
Jun 29, 2009
218
219
tmp = *ptr;
(*ptr)+= value;
Sep 17, 2009
Sep 17, 2009
220
privateUnlock(ptr);
Jun 29, 2009
Jun 29, 2009
221
222
223
return tmp;
#endif
Aug 11, 2009
Aug 11, 2009
227
SDL_AtomicFetchThenSubtract32(volatile Uint32 * ptr, Uint32 value)
Jun 29, 2009
Jun 29, 2009
229
230
#ifdef nativeFetchThenSubtract32
#else
Jul 2, 2009
Jul 2, 2009
231
Uint32 tmp = 0;
Jun 29, 2009
Jun 29, 2009
232
Sep 17, 2009
Sep 17, 2009
233
privateWaitLock(ptr);
Jun 29, 2009
Jun 29, 2009
234
235
tmp = *ptr;
(*ptr)-= value;
Sep 17, 2009
Sep 17, 2009
236
privateUnlock(ptr);
Jun 29, 2009
Jun 29, 2009
237
238
239
return tmp;
#endif
Aug 11, 2009
Aug 11, 2009
243
SDL_AtomicIncrementThenFetch32(volatile Uint32 * ptr)
Jun 29, 2009
Jun 29, 2009
245
246
#ifdef nativeIncrementThenFetch32
#else
Jul 2, 2009
Jul 2, 2009
247
Uint32 tmp = 0;
Jun 29, 2009
Jun 29, 2009
248
Sep 17, 2009
Sep 17, 2009
249
privateWaitLock(ptr);
Jun 29, 2009
Jun 29, 2009
250
251
(*ptr)+= 1;
tmp = *ptr;
Sep 17, 2009
Sep 17, 2009
252
privateUnlock(ptr);
Jun 29, 2009
Jun 29, 2009
253
254
255
return tmp;
#endif
Aug 11, 2009
Aug 11, 2009
259
SDL_AtomicDecrementThenFetch32(volatile Uint32 * ptr)
Jun 29, 2009
Jun 29, 2009
261
262
#ifdef nativeDecrementThenFetch32
#else
Jul 2, 2009
Jul 2, 2009
263
Uint32 tmp = 0;
Jun 29, 2009
Jun 29, 2009
264
Sep 17, 2009
Sep 17, 2009
265
privateWaitLock(ptr);
Jun 29, 2009
Jun 29, 2009
266
267
(*ptr)-= 1;
tmp = *ptr;
Sep 17, 2009
Sep 17, 2009
268
privateUnlock(ptr);
Jun 29, 2009
Jun 29, 2009
269
270
271
return tmp;
#endif
Aug 11, 2009
Aug 11, 2009
275
SDL_AtomicAddThenFetch32(volatile Uint32 * ptr, Uint32 value)
Jun 29, 2009
Jun 29, 2009
277
278
#ifdef nativeAddThenFetch32
#else
Jul 2, 2009
Jul 2, 2009
279
Uint32 tmp = 0;
Jun 29, 2009
Jun 29, 2009
280
Sep 17, 2009
Sep 17, 2009
281
privateWaitLock(ptr);
Jun 29, 2009
Jun 29, 2009
282
283
(*ptr)+= value;
tmp = *ptr;
Sep 17, 2009
Sep 17, 2009
284
privateUnlock(ptr);
Jun 29, 2009
Jun 29, 2009
285
286
287
return tmp;
#endif
Aug 11, 2009
Aug 11, 2009
291
SDL_AtomicSubtractThenFetch32(volatile Uint32 * ptr, Uint32 value)
Jun 29, 2009
Jun 29, 2009
293
294
#ifdef nativeSubtractThenFetch32
#else
Jul 2, 2009
Jul 2, 2009
295
Uint32 tmp = 0;
Jun 29, 2009
Jun 29, 2009
296
Sep 17, 2009
Sep 17, 2009
297
privateWaitLock(ptr);
Jun 29, 2009
Jun 29, 2009
298
299
(*ptr)-= value;
tmp = *ptr;
Sep 17, 2009
Sep 17, 2009
300
privateUnlock(ptr);
Jun 29, 2009
Jun 29, 2009
302
303
304
return tmp;
#endif
}
Jun 29, 2009
Jun 29, 2009
306
/* 64 bit atomic operations */
307
308
309
#ifdef SDL_HAS_64BIT_TYPE
SDL_bool
Aug 11, 2009
Aug 11, 2009
310
SDL_AtomicTestThenSet64(volatile Uint64 * ptr)
Jun 29, 2009
Jun 29, 2009
312
313
314
315
#ifdef nativeTestThenSet64
#else
SDL_bool result = SDL_FALSE;
Sep 17, 2009
Sep 17, 2009
316
privateWaitLock(ptr);
Jun 29, 2009
Jun 29, 2009
317
318
319
320
321
result = (*ptr == 0);
if (result)
{
*ptr = 1;
}
Sep 17, 2009
Sep 17, 2009
322
privateUnlock(ptr);
Jun 29, 2009
Jun 29, 2009
323
324
325
return result;
#endif
Aug 11, 2009
Aug 11, 2009
329
SDL_AtomicClear64(volatile Uint64 * ptr)
Jun 29, 2009
Jun 29, 2009
331
332
#ifdef nativeClear64
#else
Sep 17, 2009
Sep 17, 2009
333
privateWaitLock(ptr);
Jun 29, 2009
Jun 29, 2009
334
*ptr = 0;
Sep 17, 2009
Sep 17, 2009
335
privateUnlock(ptr);
Jun 29, 2009
Jun 29, 2009
336
337
338
return;
#endif
Aug 11, 2009
Aug 11, 2009
342
SDL_AtomicFetchThenIncrement64(volatile Uint64 * ptr)
Jun 29, 2009
Jun 29, 2009
344
345
#ifdef nativeFetchThenIncrement64
#else
Jul 2, 2009
Jul 2, 2009
346
Uint64 tmp = 0;
Jun 29, 2009
Jun 29, 2009
347
Sep 17, 2009
Sep 17, 2009
348
privateWaitLock(ptr);
Jun 29, 2009
Jun 29, 2009
349
350
tmp = *ptr;
(*ptr)+= 1;
Sep 17, 2009
Sep 17, 2009
351
privateUnlock(ptr);
Jun 29, 2009
Jun 29, 2009
352
353
354
return tmp;
#endif
Aug 11, 2009
Aug 11, 2009
358
SDL_AtomicFetchThenDecrement64(volatile Uint64 * ptr)
Jun 29, 2009
Jun 29, 2009
360
361
#ifdef nativeFetchThenDecrement64
#else
Jul 2, 2009
Jul 2, 2009
362
Uint64 tmp = 0;
Jun 29, 2009
Jun 29, 2009
363
Sep 17, 2009
Sep 17, 2009
364
privateWaitLock(ptr);
Jun 29, 2009
Jun 29, 2009
365
366
tmp = *ptr;
(*ptr) -= 1;
Sep 17, 2009
Sep 17, 2009
367
privateUnlock(ptr);
Jun 29, 2009
Jun 29, 2009
368
369
370
return tmp;
#endif
Aug 11, 2009
Aug 11, 2009
374
SDL_AtomicFetchThenAdd64(volatile Uint64 * ptr, Uint64 value)
Jun 29, 2009
Jun 29, 2009
376
377
#ifdef nativeFetchThenAdd64
#else
Jul 2, 2009
Jul 2, 2009
378
Uint64 tmp = 0;
Jun 29, 2009
Jun 29, 2009
379
Sep 17, 2009
Sep 17, 2009
380
privateWaitLock(ptr);
Jun 29, 2009
Jun 29, 2009
381
382
tmp = *ptr;
(*ptr)+= value;
Sep 17, 2009
Sep 17, 2009
383
privateUnlock(ptr);
Jun 29, 2009
Jun 29, 2009
384
385
386
return tmp;
#endif
Aug 11, 2009
Aug 11, 2009
390
SDL_AtomicFetchThenSubtract64(volatile Uint64 * ptr, Uint64 value)
Jun 29, 2009
Jun 29, 2009
392
393
#ifdef nativeFetchThenSubtract64
#else
Jul 2, 2009
Jul 2, 2009
394
Uint64 tmp = 0;
Jun 29, 2009
Jun 29, 2009
395
Sep 17, 2009
Sep 17, 2009
396
privateWaitLock(ptr);
Jun 29, 2009
Jun 29, 2009
397
398
tmp = *ptr;
(*ptr)-= value;
Sep 17, 2009
Sep 17, 2009
399
privateUnlock(ptr);
Jun 29, 2009
Jun 29, 2009
400
401
402
return tmp;
#endif
Aug 11, 2009
Aug 11, 2009
406
SDL_AtomicIncrementThenFetch64(volatile Uint64 * ptr)
Jun 29, 2009
Jun 29, 2009
408
409
#ifdef nativeIncrementThenFetch64
#else
Jul 2, 2009
Jul 2, 2009
410
Uint64 tmp = 0;
Jun 29, 2009
Jun 29, 2009
411
Sep 17, 2009
Sep 17, 2009
412
privateWaitLock(ptr);
Jun 29, 2009
Jun 29, 2009
413
414
(*ptr)+= 1;
tmp = *ptr;
Sep 17, 2009
Sep 17, 2009
415
privateUnlock(ptr);
Jun 29, 2009
Jun 29, 2009
416
417
418
return tmp;
#endif
Aug 11, 2009
Aug 11, 2009
422
SDL_AtomicDecrementThenFetch64(volatile Uint64 * ptr)
Jun 29, 2009
Jun 29, 2009
424
425
#ifdef nativeDecrementThenFetch64
#else
Jul 2, 2009
Jul 2, 2009
426
Uint64 tmp = 0;
Jun 29, 2009
Jun 29, 2009
427
Sep 17, 2009
Sep 17, 2009
428
privateWaitLock(ptr);
Jun 29, 2009
Jun 29, 2009
429
430
(*ptr)-= 1;
tmp = *ptr;
Sep 17, 2009
Sep 17, 2009
431
privateUnlock(ptr);
Jun 29, 2009
Jun 29, 2009
432
433
434
return tmp;
#endif
Aug 11, 2009
Aug 11, 2009
438
SDL_AtomicAddThenFetch64(volatile Uint64 * ptr, Uint64 value)
Jun 29, 2009
Jun 29, 2009
440
441
#ifdef nativeAddThenFetch64
#else
Jul 2, 2009
Jul 2, 2009
442
Uint64 tmp = 0;
Jun 29, 2009
Jun 29, 2009
443
Sep 17, 2009
Sep 17, 2009
444
privateWaitLock(ptr);
Jun 29, 2009
Jun 29, 2009
445
446
(*ptr)+= value;
tmp = *ptr;
Sep 17, 2009
Sep 17, 2009
447
privateUnlock(ptr);
Jun 29, 2009
Jun 29, 2009
448
449
450
return tmp;
#endif
Aug 11, 2009
Aug 11, 2009
454
SDL_AtomicSubtractThenFetch64(volatile Uint64 * ptr, Uint64 value)
Jun 29, 2009
Jun 29, 2009
456
457
#ifdef nativeSubtractThenFetch64
#else
Jul 2, 2009
Jul 2, 2009
458
Uint64 tmp = 0;
Sep 17, 2009
Sep 17, 2009
460
privateWaitLock(ptr);
Jun 29, 2009
Jun 29, 2009
461
462
(*ptr)-= value;
tmp = *ptr;
Sep 17, 2009
Sep 17, 2009
463
privateUnlock(ptr);
Jun 29, 2009
Jun 29, 2009
464
465
return tmp;
Jun 29, 2009
Jun 29, 2009
467
}