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

Latest commit

 

History

History
512 lines (414 loc) · 9.67 KB

SDL_atomic.c

File metadata and controls

512 lines (414 loc) · 9.67 KB
 
Sep 17, 2009
Sep 17, 2009
2
3
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2009 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"
Dec 13, 2009
Dec 13, 2009
28
29
30
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
Sep 17, 2009
Sep 17, 2009
31
32
#include "SDL_error.h"
Jun 29, 2009
Jun 29, 2009
33
/*
Sep 17, 2009
Sep 17, 2009
34
This file provides 32, and 64 bit atomic operations. If the
Jun 29, 2009
Jun 29, 2009
35
36
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
37
38
using the SDL spin lock operations. If spin lock can not be
implemented then these functions must fail.
Jun 29, 2009
Jun 29, 2009
39
40
41
*/
/*
Sep 25, 2009
Sep 25, 2009
42
WIN32 VERSION.
Jun 29, 2009
Jun 29, 2009
43
Sep 25, 2009
Sep 25, 2009
44
This makes use of native Windows atomic operations.
Sep 17, 2009
Sep 17, 2009
45
*/
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 25, 2009
Sep 25, 2009
55
56
57
58
59
60
61
62
63
long volatile * l = (long volatile *)lock;
Uint32 old = 0;
Uint32 new = 1;
old = InterlockedExchange(l, new);
while(1 == old)
{
old = InterlockedExchange(l, new);
}
Jun 29, 2009
Jun 29, 2009
64
65
}
Sep 17, 2009
Sep 17, 2009
66
67
void
SDL_AtomicUnlock(SDL_SpinLock *lock)
Jun 29, 2009
Jun 29, 2009
68
{
Sep 25, 2009
Sep 25, 2009
69
70
71
72
long volatile * l = (long volatile *)lock;
Uint32 new = 0;
InterlockedExchange(l, new);
Jun 29, 2009
Jun 29, 2009
73
74
}
Sep 17, 2009
Sep 17, 2009
75
76
77
78
79
/*
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
80
Sep 25, 2009
Sep 25, 2009
81
82
83
84
85
86
87
88
89
90
#define nativeTestThenSet32
#define nativeClear32
#define nativeFetchThenIncrement32
#define nativeFetchThenDecrement32
#define nativeFetchThenAdd32
#define nativeFetchThenSubtract32
#define nativeIncrementThenFetch32
#define nativeDecrementThenFetch32
#define nativeAddThenFetch32
#define nativeSubtractThenFetch32
Sep 17, 2009
Sep 17, 2009
91
92
93
94
95
96
97
98
99
100
101
#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
102
Sep 17, 2009
Sep 17, 2009
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/*
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
121
the new size is a power of two.
Sep 17, 2009
Sep 17, 2009
122
*/
Jun 29, 2009
Jun 29, 2009
123
Sep 17, 2009
Sep 17, 2009
124
125
126
127
128
129
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
130
Sep 17, 2009
Sep 17, 2009
131
132
static __inline__ void
privateWaitLock(volatile void *ptr)
Jun 29, 2009
Jun 29, 2009
133
{
Sep 17, 2009
Sep 17, 2009
134
135
136
137
#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
138
139
#endif
Sep 17, 2009
Sep 17, 2009
140
SDL_AtomicLock(&locks[index]);
Jun 29, 2009
Jun 29, 2009
141
142
}
Sep 17, 2009
Sep 17, 2009
143
144
static __inline__ void
privateUnlock(volatile void *ptr)
Jun 29, 2009
Jun 29, 2009
145
{
Sep 17, 2009
Sep 17, 2009
146
147
148
149
#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
150
151
#endif
Sep 17, 2009
Sep 17, 2009
152
SDL_AtomicUnlock(&locks[index]);
Jun 29, 2009
Jun 29, 2009
153
154
155
156
}
/* 32 bit atomic operations */
Sep 17, 2009
Sep 17, 2009
158
SDL_AtomicTestThenSet32(volatile Uint32 * ptr)
Jun 29, 2009
Jun 29, 2009
160
#ifdef nativeTestThenSet32
Sep 25, 2009
Sep 25, 2009
161
162
163
164
long volatile * p = (long volatile *)ptr;
Uint32 new = 1;
return 0 == InterlockedExchange(p, new);
Jun 29, 2009
Jun 29, 2009
165
166
167
#else
SDL_bool result = SDL_FALSE;
Sep 17, 2009
Sep 17, 2009
168
privateWaitLock(ptr);
Jun 29, 2009
Jun 29, 2009
169
170
171
172
173
result = (*ptr == 0);
if (result)
{
*ptr = 1;
}
Sep 17, 2009
Sep 17, 2009
174
privateUnlock(ptr);
Jun 29, 2009
Jun 29, 2009
175
176
177
return result;
#endif
Sep 17, 2009
Sep 17, 2009
181
SDL_AtomicClear32(volatile Uint32 * ptr)
Jun 29, 2009
Jun 29, 2009
183
#ifdef nativeClear32
Sep 25, 2009
Sep 25, 2009
184
185
186
187
long volatile * p = (long volatile *)ptr;
Uint32 new = 0;
InterlockedExchange(p, new);
Jun 29, 2009
Jun 29, 2009
188
#else
Sep 17, 2009
Sep 17, 2009
189
privateWaitLock(ptr);
Jun 29, 2009
Jun 29, 2009
190
*ptr = 0;
Sep 17, 2009
Sep 17, 2009
191
privateUnlock(ptr);
Jun 29, 2009
Jun 29, 2009
192
193
194
return;
#endif
Sep 17, 2009
Sep 17, 2009
198
SDL_AtomicFetchThenIncrement32(volatile Uint32 * ptr)
Jun 29, 2009
Jun 29, 2009
200
#ifdef nativeFetchThenIncrement32
Sep 25, 2009
Sep 25, 2009
201
202
203
long volatile * p = (long volatile *)ptr;
return InterlockedExchangeAdd(p, 1);
Jun 29, 2009
Jun 29, 2009
204
#else
Jul 2, 2009
Jul 2, 2009
205
Uint32 tmp = 0;
Jun 29, 2009
Jun 29, 2009
206
Sep 17, 2009
Sep 17, 2009
207
privateWaitLock(ptr);
Jun 29, 2009
Jun 29, 2009
208
209
tmp = *ptr;
(*ptr)+= 1;
Sep 17, 2009
Sep 17, 2009
210
privateUnlock(ptr);
Jun 29, 2009
Jun 29, 2009
211
212
213
return tmp;
#endif
Sep 17, 2009
Sep 17, 2009
217
SDL_AtomicFetchThenDecrement32(volatile Uint32 * ptr)
Jun 29, 2009
Jun 29, 2009
219
#ifdef nativeFetchThenDecrement32
Sep 25, 2009
Sep 25, 2009
220
221
222
long volatile * p = (long volatile *)ptr;
return InterlockedExchangeAdd(p, -1);
Jun 29, 2009
Jun 29, 2009
223
#else
Jul 2, 2009
Jul 2, 2009
224
Uint32 tmp = 0;
Jun 29, 2009
Jun 29, 2009
225
Sep 17, 2009
Sep 17, 2009
226
privateWaitLock(ptr);
Jun 29, 2009
Jun 29, 2009
227
228
tmp = *ptr;
(*ptr) -= 1;
Sep 17, 2009
Sep 17, 2009
229
privateUnlock(ptr);
Jun 29, 2009
Jun 29, 2009
230
231
232
return tmp;
#endif
Sep 17, 2009
Sep 17, 2009
236
SDL_AtomicFetchThenAdd32(volatile Uint32 * ptr, Uint32 value)
Jun 29, 2009
Jun 29, 2009
238
#ifdef nativeFetchThenAdd32
Sep 25, 2009
Sep 25, 2009
239
240
241
long volatile * p = (long volatile *)ptr;
return InterlockedExchangeAdd(p, value);
Jun 29, 2009
Jun 29, 2009
242
#else
Jul 2, 2009
Jul 2, 2009
243
Uint32 tmp = 0;
Jun 29, 2009
Jun 29, 2009
244
Sep 17, 2009
Sep 17, 2009
245
privateWaitLock(ptr);
Jun 29, 2009
Jun 29, 2009
246
247
tmp = *ptr;
(*ptr)+= value;
Sep 17, 2009
Sep 17, 2009
248
privateUnlock(ptr);
Jun 29, 2009
Jun 29, 2009
249
250
251
return tmp;
#endif
Sep 17, 2009
Sep 17, 2009
255
SDL_AtomicFetchThenSubtract32(volatile Uint32 * ptr, Uint32 value)
Jun 29, 2009
Jun 29, 2009
257
#ifdef nativeFetchThenSubtract32
Sep 25, 2009
Sep 25, 2009
258
259
260
long volatile * p = (long volatile *)ptr;
return InterlockedExchangeAdd(p, (0 - value));
Jun 29, 2009
Jun 29, 2009
261
#else
Jul 2, 2009
Jul 2, 2009
262
Uint32 tmp = 0;
Jun 29, 2009
Jun 29, 2009
263
Sep 17, 2009
Sep 17, 2009
264
privateWaitLock(ptr);
Jun 29, 2009
Jun 29, 2009
265
266
tmp = *ptr;
(*ptr)-= value;
Sep 17, 2009
Sep 17, 2009
267
privateUnlock(ptr);
Jun 29, 2009
Jun 29, 2009
268
269
270
return tmp;
#endif
Sep 17, 2009
Sep 17, 2009
274
SDL_AtomicIncrementThenFetch32(volatile Uint32 * ptr)
Jun 29, 2009
Jun 29, 2009
276
#ifdef nativeIncrementThenFetch32
Sep 25, 2009
Sep 25, 2009
277
278
279
long volatile * p = (LONG volatile *)ptr;
return InterlockedIncrement(p);
Jun 29, 2009
Jun 29, 2009
280
#else
Jul 2, 2009
Jul 2, 2009
281
Uint32 tmp = 0;
Jun 29, 2009
Jun 29, 2009
282
Sep 17, 2009
Sep 17, 2009
283
privateWaitLock(ptr);
Jun 29, 2009
Jun 29, 2009
284
285
(*ptr)+= 1;
tmp = *ptr;
Sep 17, 2009
Sep 17, 2009
286
privateUnlock(ptr);
Jun 29, 2009
Jun 29, 2009
287
288
289
return tmp;
#endif
Sep 17, 2009
Sep 17, 2009
293
SDL_AtomicDecrementThenFetch32(volatile Uint32 * ptr)
Jun 29, 2009
Jun 29, 2009
295
#ifdef nativeDecrementThenFetch32
Sep 25, 2009
Sep 25, 2009
296
297
298
long volatile * p = (LONG volatile *)ptr;
return InterlockedDecrement(p);
Jun 29, 2009
Jun 29, 2009
299
#else
Jul 2, 2009
Jul 2, 2009
300
Uint32 tmp = 0;
Jun 29, 2009
Jun 29, 2009
301
Sep 17, 2009
Sep 17, 2009
302
privateWaitLock(ptr);
Jun 29, 2009
Jun 29, 2009
303
304
(*ptr)-= 1;
tmp = *ptr;
Sep 17, 2009
Sep 17, 2009
305
privateUnlock(ptr);
Jun 29, 2009
Jun 29, 2009
306
307
308
return tmp;
#endif
Sep 17, 2009
Sep 17, 2009
312
SDL_AtomicAddThenFetch32(volatile Uint32 * ptr, Uint32 value)
Jun 29, 2009
Jun 29, 2009
314
#ifdef nativeAddThenFetch32
Sep 25, 2009
Sep 25, 2009
315
316
317
long volatile * p = (long volatile *)ptr;
return InterlockedExchangeAdd(p, value) + value;
Jun 29, 2009
Jun 29, 2009
318
#else
Jul 2, 2009
Jul 2, 2009
319
Uint32 tmp = 0;
Jun 29, 2009
Jun 29, 2009
320
Sep 17, 2009
Sep 17, 2009
321
privateWaitLock(ptr);
Jun 29, 2009
Jun 29, 2009
322
323
(*ptr)+= value;
tmp = *ptr;
Sep 17, 2009
Sep 17, 2009
324
privateUnlock(ptr);
Jun 29, 2009
Jun 29, 2009
325
326
327
return tmp;
#endif
Sep 17, 2009
Sep 17, 2009
331
SDL_AtomicSubtractThenFetch32(volatile Uint32 * ptr, Uint32 value)
Jun 29, 2009
Jun 29, 2009
333
#ifdef nativeSubtractThenFetch32
Sep 25, 2009
Sep 25, 2009
334
335
336
long volatile * p = (long volatile *)ptr;
return InterlockedExchangeAdd(p, (0 - value)) - value;
Jun 29, 2009
Jun 29, 2009
337
#else
Jul 2, 2009
Jul 2, 2009
338
Uint32 tmp = 0;
Jun 29, 2009
Jun 29, 2009
339
Sep 17, 2009
Sep 17, 2009
340
privateWaitLock(ptr);
Jun 29, 2009
Jun 29, 2009
341
342
(*ptr)-= value;
tmp = *ptr;
Sep 17, 2009
Sep 17, 2009
343
privateUnlock(ptr);
Jun 29, 2009
Jun 29, 2009
345
346
347
return tmp;
#endif
}
Jun 29, 2009
Jun 29, 2009
349
/* 64 bit atomic operations */
350
351
352
#ifdef SDL_HAS_64BIT_TYPE
SDL_bool
Sep 17, 2009
Sep 17, 2009
353
SDL_AtomicTestThenSet64(volatile Uint64 * ptr)
Jun 29, 2009
Jun 29, 2009
355
356
357
358
#ifdef nativeTestThenSet64
#else
SDL_bool result = SDL_FALSE;
Sep 17, 2009
Sep 17, 2009
359
privateWaitLock(ptr);
Jun 29, 2009
Jun 29, 2009
360
361
362
363
364
result = (*ptr == 0);
if (result)
{
*ptr = 1;
}
Sep 17, 2009
Sep 17, 2009
365
privateUnlock(ptr);
Jun 29, 2009
Jun 29, 2009
366
367
368
return result;
#endif
Sep 17, 2009
Sep 17, 2009
372
SDL_AtomicClear64(volatile Uint64 * ptr)
Jun 29, 2009
Jun 29, 2009
374
375
#ifdef nativeClear64
#else
Sep 17, 2009
Sep 17, 2009
376
privateWaitLock(ptr);
Jun 29, 2009
Jun 29, 2009
377
*ptr = 0;
Sep 17, 2009
Sep 17, 2009
378
privateUnlock(ptr);
Jun 29, 2009
Jun 29, 2009
379
380
381
return;
#endif
Sep 17, 2009
Sep 17, 2009
385
SDL_AtomicFetchThenIncrement64(volatile Uint64 * ptr)
Jun 29, 2009
Jun 29, 2009
387
388
#ifdef nativeFetchThenIncrement64
#else
Jul 2, 2009
Jul 2, 2009
389
Uint64 tmp = 0;
Jun 29, 2009
Jun 29, 2009
390
Sep 17, 2009
Sep 17, 2009
391
privateWaitLock(ptr);
Jun 29, 2009
Jun 29, 2009
392
393
tmp = *ptr;
(*ptr)+= 1;
Sep 17, 2009
Sep 17, 2009
394
privateUnlock(ptr);
Jun 29, 2009
Jun 29, 2009
395
396
397
return tmp;
#endif
Sep 17, 2009
Sep 17, 2009
401
SDL_AtomicFetchThenDecrement64(volatile Uint64 * ptr)
Jun 29, 2009
Jun 29, 2009
403
404
#ifdef nativeFetchThenDecrement64
#else
Jul 2, 2009
Jul 2, 2009
405
Uint64 tmp = 0;
Jun 29, 2009
Jun 29, 2009
406
Sep 17, 2009
Sep 17, 2009
407
privateWaitLock(ptr);
Jun 29, 2009
Jun 29, 2009
408
409
tmp = *ptr;
(*ptr) -= 1;
Sep 17, 2009
Sep 17, 2009
410
privateUnlock(ptr);
Jun 29, 2009
Jun 29, 2009
411
412
413
return tmp;
#endif
Sep 17, 2009
Sep 17, 2009
417
SDL_AtomicFetchThenAdd64(volatile Uint64 * ptr, Uint64 value)
Jun 29, 2009
Jun 29, 2009
419
420
#ifdef nativeFetchThenAdd64
#else
Jul 2, 2009
Jul 2, 2009
421
Uint64 tmp = 0;
Jun 29, 2009
Jun 29, 2009
422
Sep 17, 2009
Sep 17, 2009
423
privateWaitLock(ptr);
Jun 29, 2009
Jun 29, 2009
424
425
tmp = *ptr;
(*ptr)+= value;
Sep 17, 2009
Sep 17, 2009
426
privateUnlock(ptr);
Jun 29, 2009
Jun 29, 2009
427
428
429
return tmp;
#endif
Sep 17, 2009
Sep 17, 2009
433
SDL_AtomicFetchThenSubtract64(volatile Uint64 * ptr, Uint64 value)
Jun 29, 2009
Jun 29, 2009
435
436
#ifdef nativeFetchThenSubtract64
#else
Jul 2, 2009
Jul 2, 2009
437
Uint64 tmp = 0;
Jun 29, 2009
Jun 29, 2009
438
Sep 17, 2009
Sep 17, 2009
439
privateWaitLock(ptr);
Jun 29, 2009
Jun 29, 2009
440
441
tmp = *ptr;
(*ptr)-= value;
Sep 17, 2009
Sep 17, 2009
442
privateUnlock(ptr);
Jun 29, 2009
Jun 29, 2009
443
444
445
return tmp;
#endif
Sep 17, 2009
Sep 17, 2009
449
SDL_AtomicIncrementThenFetch64(volatile Uint64 * ptr)
Jun 29, 2009
Jun 29, 2009
451
452
#ifdef nativeIncrementThenFetch64
#else
Jul 2, 2009
Jul 2, 2009
453
Uint64 tmp = 0;
Jun 29, 2009
Jun 29, 2009
454
Sep 17, 2009
Sep 17, 2009
455
privateWaitLock(ptr);
Jun 29, 2009
Jun 29, 2009
456
457
(*ptr)+= 1;
tmp = *ptr;
Sep 17, 2009
Sep 17, 2009
458
privateUnlock(ptr);
Jun 29, 2009
Jun 29, 2009
459
460
461
return tmp;
#endif
Sep 17, 2009
Sep 17, 2009
465
SDL_AtomicDecrementThenFetch64(volatile Uint64 * ptr)
Jun 29, 2009
Jun 29, 2009
467
468
#ifdef nativeDecrementThenFetch64
#else
Jul 2, 2009
Jul 2, 2009
469
Uint64 tmp = 0;
Jun 29, 2009
Jun 29, 2009
470
Sep 17, 2009
Sep 17, 2009
471
privateWaitLock(ptr);
Jun 29, 2009
Jun 29, 2009
472
473
(*ptr)-= 1;
tmp = *ptr;
Sep 17, 2009
Sep 17, 2009
474
privateUnlock(ptr);
Jun 29, 2009
Jun 29, 2009
475
476
477
return tmp;
#endif
Sep 17, 2009
Sep 17, 2009
481
SDL_AtomicAddThenFetch64(volatile Uint64 * ptr, Uint64 value)
Jun 29, 2009
Jun 29, 2009
483
484
#ifdef nativeAddThenFetch64
#else
Jul 2, 2009
Jul 2, 2009
485
Uint64 tmp = 0;
Jun 29, 2009
Jun 29, 2009
486
Sep 17, 2009
Sep 17, 2009
487
privateWaitLock(ptr);
Jun 29, 2009
Jun 29, 2009
488
489
(*ptr)+= value;
tmp = *ptr;
Sep 17, 2009
Sep 17, 2009
490
privateUnlock(ptr);
Jun 29, 2009
Jun 29, 2009
491
492
493
return tmp;
#endif
Sep 17, 2009
Sep 17, 2009
497
SDL_AtomicSubtractThenFetch64(volatile Uint64 * ptr, Uint64 value)
Jun 29, 2009
Jun 29, 2009
499
500
#ifdef nativeSubtractThenFetch64
#else
Jul 2, 2009
Jul 2, 2009
501
Uint64 tmp = 0;
Sep 17, 2009
Sep 17, 2009
503
privateWaitLock(ptr);
Jun 29, 2009
Jun 29, 2009
504
505
(*ptr)-= value;
tmp = *ptr;
Sep 17, 2009
Sep 17, 2009
506
privateUnlock(ptr);
Jun 29, 2009
Jun 29, 2009
507
508
return tmp;
Jun 29, 2009
Jun 29, 2009
510
}