Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/sdl/atomic/SDL_spinlock.c
9904 views
1
/*
2
Simple DirectMedia Layer
3
Copyright (C) 1997-2025 Sam Lantinga <[email protected]>
4
5
This software is provided 'as-is', without any express or implied
6
warranty. In no event will the authors be held liable for any damages
7
arising from the use of this software.
8
9
Permission is granted to anyone to use this software for any purpose,
10
including commercial applications, and to alter it and redistribute it
11
freely, subject to the following restrictions:
12
13
1. The origin of this software must not be misrepresented; you must not
14
claim that you wrote the original software. If you use this software
15
in a product, an acknowledgment in the product documentation would be
16
appreciated but is not required.
17
2. Altered source versions must be plainly marked as such, and must not be
18
misrepresented as being the original software.
19
3. This notice may not be removed or altered from any source distribution.
20
*/
21
#include "SDL_internal.h"
22
23
#if defined(SDL_PLATFORM_WINDOWS)
24
#include "../core/windows/SDL_windows.h"
25
#endif
26
27
#if !defined(HAVE_GCC_ATOMICS) && defined(SDL_PLATFORM_SOLARIS)
28
#include <atomic.h>
29
#endif
30
31
#if !defined(HAVE_GCC_ATOMICS) && defined(SDL_PLATFORM_RISCOS)
32
#include <unixlib/local.h>
33
#endif
34
35
#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
36
#include <xmmintrin.h>
37
#endif
38
39
#ifdef PS2
40
#include <kernel.h>
41
#endif
42
43
#if !defined(HAVE_GCC_ATOMICS) && defined(SDL_PLATFORM_MACOS)
44
#include <libkern/OSAtomic.h>
45
#endif
46
47
/* *INDENT-OFF* */ // clang-format off
48
#if defined(__WATCOMC__) && defined(__386__)
49
SDL_COMPILE_TIME_ASSERT(locksize, 4==sizeof(SDL_SpinLock));
50
extern __inline int _SDL_xchg_watcom(volatile int *a, int v);
51
#pragma aux _SDL_xchg_watcom = \
52
"lock xchg [ecx], eax" \
53
parm [ecx] [eax] \
54
value [eax] \
55
modify exact [eax];
56
#endif // __WATCOMC__ && __386__
57
/* *INDENT-ON* */ // clang-format on
58
59
// This function is where all the magic happens...
60
bool SDL_TryLockSpinlock(SDL_SpinLock *lock)
61
{
62
#if defined(HAVE_GCC_ATOMICS) || defined(HAVE_GCC_SYNC_LOCK_TEST_AND_SET)
63
return __sync_lock_test_and_set(lock, 1) == 0;
64
65
#elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64))
66
return _InterlockedExchange_acq(lock, 1) == 0;
67
68
#elif defined(_MSC_VER)
69
SDL_COMPILE_TIME_ASSERT(locksize, sizeof(*lock) == sizeof(long));
70
return InterlockedExchange((long *)lock, 1) == 0;
71
72
#elif defined(__WATCOMC__) && defined(__386__)
73
return _SDL_xchg_watcom(lock, 1) == 0;
74
75
#elif defined(__GNUC__) && defined(__arm__) && \
76
(defined(__ARM_ARCH_3__) || defined(__ARM_ARCH_3M__) || \
77
defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__) || \
78
defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5TE__) || \
79
defined(__ARM_ARCH_5TEJ__))
80
int result;
81
82
#ifdef SDL_PLATFORM_RISCOS
83
if (__cpucap_have_rex()) {
84
__asm__ __volatile__(
85
"ldrex %0, [%2]\nteq %0, #0\nstrexeq %0, %1, [%2]"
86
: "=&r"(result)
87
: "r"(1), "r"(lock)
88
: "cc", "memory");
89
return result == 0;
90
}
91
#endif
92
93
__asm__ __volatile__(
94
"swp %0, %1, [%2]\n"
95
: "=&r,&r"(result)
96
: "r,0"(1), "r,r"(lock)
97
: "memory");
98
return result == 0;
99
100
#elif defined(__GNUC__) && defined(__arm__)
101
int result;
102
__asm__ __volatile__(
103
"ldrex %0, [%2]\nteq %0, #0\nstrexeq %0, %1, [%2]"
104
: "=&r"(result)
105
: "r"(1), "r"(lock)
106
: "cc", "memory");
107
return result == 0;
108
109
#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
110
int result;
111
__asm__ __volatile__(
112
"lock ; xchgl %0, (%1)\n"
113
: "=r"(result)
114
: "r"(lock), "0"(1)
115
: "cc", "memory");
116
return result == 0;
117
118
#elif defined(SDL_PLATFORM_MACOS) || defined(SDL_PLATFORM_IOS) || defined(SDL_PLATFORM_TVOS)
119
// Maybe used for PowerPC, but the Intel asm or gcc atomics are favored.
120
return OSAtomicCompareAndSwap32Barrier(0, 1, lock);
121
122
#elif defined(SDL_PLATFORM_SOLARIS) && defined(_LP64)
123
// Used for Solaris with non-gcc compilers.
124
return ((int)atomic_cas_64((volatile uint64_t *)lock, 0, 1) == 0);
125
126
#elif defined(SDL_PLATFORM_SOLARIS) && !defined(_LP64)
127
// Used for Solaris with non-gcc compilers.
128
return ((int)atomic_cas_32((volatile uint32_t *)lock, 0, 1) == 0);
129
#elif defined(PS2)
130
uint32_t oldintr;
131
bool res = false;
132
// disable interruption
133
oldintr = DIntr();
134
135
if (*lock == 0) {
136
*lock = 1;
137
res = true;
138
}
139
// enable interruption
140
if (oldintr) {
141
EIntr();
142
}
143
return res;
144
#else
145
// Terrible terrible damage
146
static SDL_Mutex *_spinlock_mutex;
147
148
if (!_spinlock_mutex) {
149
// Race condition on first lock...
150
_spinlock_mutex = SDL_CreateMutex();
151
}
152
SDL_LockMutex(_spinlock_mutex);
153
if (*lock == 0) {
154
*lock = 1;
155
SDL_UnlockMutex(_spinlock_mutex);
156
return true;
157
} else {
158
SDL_UnlockMutex(_spinlock_mutex);
159
return false;
160
}
161
#endif
162
}
163
164
void SDL_LockSpinlock(SDL_SpinLock *lock)
165
{
166
int iterations = 0;
167
// FIXME: Should we have an eventual timeout?
168
while (!SDL_TryLockSpinlock(lock)) {
169
if (iterations < 32) {
170
iterations++;
171
SDL_CPUPauseInstruction();
172
} else {
173
// !!! FIXME: this doesn't definitely give up the current timeslice, it does different things on various platforms.
174
SDL_Delay(0);
175
}
176
}
177
}
178
179
void SDL_UnlockSpinlock(SDL_SpinLock *lock)
180
{
181
#if defined(HAVE_GCC_ATOMICS) || defined(HAVE_GCC_SYNC_LOCK_TEST_AND_SET)
182
__sync_lock_release(lock);
183
184
#elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64))
185
_InterlockedExchange_rel(lock, 0);
186
187
#elif defined(_MSC_VER)
188
_ReadWriteBarrier();
189
*lock = 0;
190
191
#elif defined(__WATCOMC__) && defined(__386__)
192
SDL_CompilerBarrier();
193
*lock = 0;
194
195
#elif defined(SDL_PLATFORM_SOLARIS)
196
// Used for Solaris when not using gcc.
197
*lock = 0;
198
membar_producer();
199
200
#else
201
*lock = 0;
202
#endif
203
}
204
205