Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/sdl/thread/windows/SDL_sysmutex.c
9905 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
#ifdef SDL_THREAD_WINDOWS
24
25
/**
26
* Mutex functions using the Win32 API
27
* There are two implementations available based on:
28
* - Critical Sections. Available on all OS versions since Windows XP.
29
* - Slim Reader/Writer Locks. Requires Windows 7 or newer.
30
* which are chosen at runtime.
31
*/
32
33
#include "SDL_sysmutex_c.h"
34
35
// Implementation will be chosen at runtime based on available Kernel features
36
SDL_mutex_impl_t SDL_mutex_impl_active = { 0 };
37
38
/**
39
* Implementation based on Slim Reader/Writer (SRW) Locks for Win 7 and newer.
40
*/
41
42
typedef VOID(WINAPI *pfnInitializeSRWLock)(PSRWLOCK);
43
typedef VOID(WINAPI *pfnReleaseSRWLockExclusive)(PSRWLOCK);
44
typedef VOID(WINAPI *pfnAcquireSRWLockExclusive)(PSRWLOCK);
45
typedef BOOLEAN(WINAPI *pfnTryAcquireSRWLockExclusive)(PSRWLOCK);
46
static pfnInitializeSRWLock pInitializeSRWLock = NULL;
47
static pfnReleaseSRWLockExclusive pReleaseSRWLockExclusive = NULL;
48
static pfnAcquireSRWLockExclusive pAcquireSRWLockExclusive = NULL;
49
static pfnTryAcquireSRWLockExclusive pTryAcquireSRWLockExclusive = NULL;
50
51
static SDL_Mutex *SDL_CreateMutex_srw(void)
52
{
53
SDL_mutex_srw *mutex = (SDL_mutex_srw *)SDL_calloc(1, sizeof(*mutex));
54
if (mutex) {
55
pInitializeSRWLock(&mutex->srw);
56
}
57
return (SDL_Mutex *)mutex;
58
}
59
60
static void SDL_DestroyMutex_srw(SDL_Mutex *mutex)
61
{
62
// There are no kernel allocated resources
63
SDL_free(mutex);
64
}
65
66
static void SDL_LockMutex_srw(SDL_Mutex *_mutex) SDL_NO_THREAD_SAFETY_ANALYSIS // clang doesn't know about NULL mutexes
67
{
68
SDL_mutex_srw *mutex = (SDL_mutex_srw *)_mutex;
69
const DWORD this_thread = GetCurrentThreadId();
70
71
if (mutex->owner == this_thread) {
72
++mutex->count;
73
} else {
74
/* The order of operations is important.
75
We set the locking thread id after we obtain the lock
76
so unlocks from other threads will fail.
77
*/
78
pAcquireSRWLockExclusive(&mutex->srw);
79
SDL_assert(mutex->count == 0 && mutex->owner == 0);
80
mutex->owner = this_thread;
81
mutex->count = 1;
82
}
83
}
84
85
static bool SDL_TryLockMutex_srw(SDL_Mutex *_mutex)
86
{
87
SDL_mutex_srw *mutex = (SDL_mutex_srw *)_mutex;
88
const DWORD this_thread = GetCurrentThreadId();
89
bool retval = true;
90
91
if (mutex->owner == this_thread) {
92
++mutex->count;
93
} else {
94
if (pTryAcquireSRWLockExclusive(&mutex->srw) != 0) {
95
SDL_assert(mutex->count == 0 && mutex->owner == 0);
96
mutex->owner = this_thread;
97
mutex->count = 1;
98
} else {
99
retval = false;
100
}
101
}
102
return retval;
103
}
104
105
static void SDL_UnlockMutex_srw(SDL_Mutex *_mutex) SDL_NO_THREAD_SAFETY_ANALYSIS // clang doesn't know about NULL mutexes
106
{
107
SDL_mutex_srw *mutex = (SDL_mutex_srw *)_mutex;
108
109
if (mutex->owner == GetCurrentThreadId()) {
110
if (--mutex->count == 0) {
111
mutex->owner = 0;
112
pReleaseSRWLockExclusive(&mutex->srw);
113
}
114
} else {
115
SDL_assert(!"mutex not owned by this thread"); // undefined behavior...!
116
}
117
}
118
119
static const SDL_mutex_impl_t SDL_mutex_impl_srw = {
120
&SDL_CreateMutex_srw,
121
&SDL_DestroyMutex_srw,
122
&SDL_LockMutex_srw,
123
&SDL_TryLockMutex_srw,
124
&SDL_UnlockMutex_srw,
125
SDL_MUTEX_SRW,
126
};
127
128
/**
129
* Fallback Mutex implementation using Critical Sections (before Win 7)
130
*/
131
132
static SDL_Mutex *SDL_CreateMutex_cs(void)
133
{
134
SDL_mutex_cs *mutex = (SDL_mutex_cs *)SDL_malloc(sizeof(*mutex));
135
if (mutex) {
136
// Initialize
137
// On SMP systems, a non-zero spin count generally helps performance
138
// This function always succeeds
139
(void)InitializeCriticalSectionAndSpinCount(&mutex->cs, 2000);
140
}
141
return (SDL_Mutex *)mutex;
142
}
143
144
static void SDL_DestroyMutex_cs(SDL_Mutex *mutex_)
145
{
146
SDL_mutex_cs *mutex = (SDL_mutex_cs *)mutex_;
147
DeleteCriticalSection(&mutex->cs);
148
SDL_free(mutex);
149
}
150
151
static void SDL_LockMutex_cs(SDL_Mutex *mutex_) SDL_NO_THREAD_SAFETY_ANALYSIS // clang doesn't know about NULL mutexes
152
{
153
SDL_mutex_cs *mutex = (SDL_mutex_cs *)mutex_;
154
EnterCriticalSection(&mutex->cs);
155
}
156
157
static bool SDL_TryLockMutex_cs(SDL_Mutex *mutex_)
158
{
159
SDL_mutex_cs *mutex = (SDL_mutex_cs *)mutex_;
160
return (TryEnterCriticalSection(&mutex->cs) == TRUE);
161
}
162
163
static void SDL_UnlockMutex_cs(SDL_Mutex *mutex_) SDL_NO_THREAD_SAFETY_ANALYSIS // clang doesn't know about NULL mutexes
164
{
165
SDL_mutex_cs *mutex = (SDL_mutex_cs *)mutex_;
166
LeaveCriticalSection(&mutex->cs);
167
}
168
169
static const SDL_mutex_impl_t SDL_mutex_impl_cs = {
170
&SDL_CreateMutex_cs,
171
&SDL_DestroyMutex_cs,
172
&SDL_LockMutex_cs,
173
&SDL_TryLockMutex_cs,
174
&SDL_UnlockMutex_cs,
175
SDL_MUTEX_CS,
176
};
177
178
/**
179
* Runtime selection and redirection
180
*/
181
182
SDL_Mutex *SDL_CreateMutex(void)
183
{
184
if (!SDL_mutex_impl_active.Create) {
185
const SDL_mutex_impl_t *impl = &SDL_mutex_impl_cs;
186
187
// Try faster implementation for Windows 7 and newer
188
HMODULE kernel32 = GetModuleHandle(TEXT("kernel32.dll"));
189
if (kernel32) {
190
// Requires Vista:
191
pInitializeSRWLock = (pfnInitializeSRWLock)GetProcAddress(kernel32, "InitializeSRWLock");
192
pReleaseSRWLockExclusive = (pfnReleaseSRWLockExclusive)GetProcAddress(kernel32, "ReleaseSRWLockExclusive");
193
pAcquireSRWLockExclusive = (pfnAcquireSRWLockExclusive)GetProcAddress(kernel32, "AcquireSRWLockExclusive");
194
// Requires 7:
195
pTryAcquireSRWLockExclusive = (pfnTryAcquireSRWLockExclusive)GetProcAddress(kernel32, "TryAcquireSRWLockExclusive");
196
if (pInitializeSRWLock && pReleaseSRWLockExclusive && pAcquireSRWLockExclusive && pTryAcquireSRWLockExclusive) {
197
impl = &SDL_mutex_impl_srw;
198
}
199
}
200
201
// Copy instead of using pointer to save one level of indirection
202
SDL_copyp(&SDL_mutex_impl_active, impl);
203
}
204
return SDL_mutex_impl_active.Create();
205
}
206
207
void SDL_DestroyMutex(SDL_Mutex *mutex)
208
{
209
if (mutex) {
210
SDL_mutex_impl_active.Destroy(mutex);
211
}
212
}
213
214
void SDL_LockMutex(SDL_Mutex *mutex)
215
{
216
if (mutex) {
217
SDL_mutex_impl_active.Lock(mutex);
218
}
219
}
220
221
bool SDL_TryLockMutex(SDL_Mutex *mutex)
222
{
223
bool result = true;
224
225
if (mutex) {
226
result = SDL_mutex_impl_active.TryLock(mutex);
227
}
228
return result;
229
}
230
231
void SDL_UnlockMutex(SDL_Mutex *mutex)
232
{
233
if (mutex) {
234
SDL_mutex_impl_active.Unlock(mutex);
235
}
236
}
237
238
#endif // SDL_THREAD_WINDOWS
239
240