Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/sdl/thread/windows/SDL_sysrwlock_srw.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
/**
24
* Implementation based on Slim Reader/Writer (SRW) Locks for Win 7 and newer.
25
*/
26
27
// This header makes sure SRWLOCK is actually declared, even on ancient WinSDKs.
28
#include "SDL_sysmutex_c.h"
29
30
typedef VOID(WINAPI *pfnInitializeSRWLock)(PSRWLOCK);
31
typedef VOID(WINAPI *pfnReleaseSRWLockShared)(PSRWLOCK);
32
typedef VOID(WINAPI *pfnAcquireSRWLockShared)(PSRWLOCK);
33
typedef BOOLEAN(WINAPI *pfnTryAcquireSRWLockShared)(PSRWLOCK);
34
typedef VOID(WINAPI *pfnReleaseSRWLockExclusive)(PSRWLOCK);
35
typedef VOID(WINAPI *pfnAcquireSRWLockExclusive)(PSRWLOCK);
36
typedef BOOLEAN(WINAPI *pfnTryAcquireSRWLockExclusive)(PSRWLOCK);
37
38
static pfnInitializeSRWLock pInitializeSRWLock = NULL;
39
static pfnReleaseSRWLockShared pReleaseSRWLockShared = NULL;
40
static pfnAcquireSRWLockShared pAcquireSRWLockShared = NULL;
41
static pfnTryAcquireSRWLockShared pTryAcquireSRWLockShared = NULL;
42
static pfnReleaseSRWLockExclusive pReleaseSRWLockExclusive = NULL;
43
static pfnAcquireSRWLockExclusive pAcquireSRWLockExclusive = NULL;
44
static pfnTryAcquireSRWLockExclusive pTryAcquireSRWLockExclusive = NULL;
45
46
typedef SDL_RWLock *(*pfnSDL_CreateRWLock)(void);
47
typedef void (*pfnSDL_DestroyRWLock)(SDL_RWLock *);
48
typedef void (*pfnSDL_LockRWLockForReading)(SDL_RWLock *);
49
typedef void (*pfnSDL_LockRWLockForWriting)(SDL_RWLock *);
50
typedef bool (*pfnSDL_TryLockRWLockForReading)(SDL_RWLock *);
51
typedef bool (*pfnSDL_TryLockRWLockForWriting)(SDL_RWLock *);
52
typedef void (*pfnSDL_UnlockRWLock)(SDL_RWLock *);
53
54
typedef struct SDL_rwlock_impl_t
55
{
56
pfnSDL_CreateRWLock Create;
57
pfnSDL_DestroyRWLock Destroy;
58
pfnSDL_LockRWLockForReading LockForReading;
59
pfnSDL_LockRWLockForWriting LockForWriting;
60
pfnSDL_TryLockRWLockForReading TryLockForReading;
61
pfnSDL_TryLockRWLockForWriting TryLockForWriting;
62
pfnSDL_UnlockRWLock Unlock;
63
} SDL_rwlock_impl_t;
64
65
// Implementation will be chosen at runtime based on available Kernel features
66
static SDL_rwlock_impl_t SDL_rwlock_impl_active = { 0 };
67
68
// rwlock implementation using Win7+ slim read/write locks (SRWLOCK)
69
70
typedef struct SDL_rwlock_srw
71
{
72
SRWLOCK srw;
73
SDL_ThreadID write_owner;
74
} SDL_rwlock_srw;
75
76
static SDL_RWLock *SDL_CreateRWLock_srw(void)
77
{
78
SDL_rwlock_srw *rwlock = (SDL_rwlock_srw *)SDL_calloc(1, sizeof(*rwlock));
79
if (rwlock) {
80
pInitializeSRWLock(&rwlock->srw);
81
}
82
return (SDL_RWLock *)rwlock;
83
}
84
85
static void SDL_DestroyRWLock_srw(SDL_RWLock *_rwlock)
86
{
87
SDL_rwlock_srw *rwlock = (SDL_rwlock_srw *) _rwlock;
88
// There are no kernel allocated resources
89
SDL_free(rwlock);
90
}
91
92
static void SDL_LockRWLockForReading_srw(SDL_RWLock *_rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS // clang doesn't know about NULL mutexes
93
{
94
SDL_rwlock_srw *rwlock = (SDL_rwlock_srw *) _rwlock;
95
pAcquireSRWLockShared(&rwlock->srw);
96
}
97
98
static void SDL_LockRWLockForWriting_srw(SDL_RWLock *_rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS // clang doesn't know about NULL mutexes
99
{
100
SDL_rwlock_srw *rwlock = (SDL_rwlock_srw *) _rwlock;
101
pAcquireSRWLockExclusive(&rwlock->srw);
102
rwlock->write_owner = SDL_GetCurrentThreadID();
103
}
104
105
static bool SDL_TryLockRWLockForReading_srw(SDL_RWLock *_rwlock)
106
{
107
SDL_rwlock_srw *rwlock = (SDL_rwlock_srw *) _rwlock;
108
return pTryAcquireSRWLockShared(&rwlock->srw);
109
}
110
111
static bool SDL_TryLockRWLockForWriting_srw(SDL_RWLock *_rwlock)
112
{
113
SDL_rwlock_srw *rwlock = (SDL_rwlock_srw *) _rwlock;
114
if (pTryAcquireSRWLockExclusive(&rwlock->srw)) {
115
rwlock->write_owner = SDL_GetCurrentThreadID();
116
return true;
117
} else {
118
return false;
119
}
120
}
121
122
static void SDL_UnlockRWLock_srw(SDL_RWLock *_rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS // clang doesn't know about NULL mutexes
123
{
124
SDL_rwlock_srw *rwlock = (SDL_rwlock_srw *) _rwlock;
125
if (rwlock->write_owner == SDL_GetCurrentThreadID()) {
126
rwlock->write_owner = 0;
127
pReleaseSRWLockExclusive(&rwlock->srw);
128
} else {
129
pReleaseSRWLockShared(&rwlock->srw);
130
}
131
}
132
133
static const SDL_rwlock_impl_t SDL_rwlock_impl_srw = {
134
&SDL_CreateRWLock_srw,
135
&SDL_DestroyRWLock_srw,
136
&SDL_LockRWLockForReading_srw,
137
&SDL_LockRWLockForWriting_srw,
138
&SDL_TryLockRWLockForReading_srw,
139
&SDL_TryLockRWLockForWriting_srw,
140
&SDL_UnlockRWLock_srw
141
};
142
143
144
#include "../generic/SDL_sysrwlock_c.h"
145
146
// Generic rwlock implementation using SDL_Mutex, SDL_Condition, and SDL_AtomicInt
147
static const SDL_rwlock_impl_t SDL_rwlock_impl_generic = {
148
&SDL_CreateRWLock_generic,
149
&SDL_DestroyRWLock_generic,
150
&SDL_LockRWLockForReading_generic,
151
&SDL_LockRWLockForWriting_generic,
152
&SDL_TryLockRWLockForReading_generic,
153
&SDL_TryLockRWLockForWriting_generic,
154
&SDL_UnlockRWLock_generic
155
};
156
157
SDL_RWLock *SDL_CreateRWLock(void)
158
{
159
if (!SDL_rwlock_impl_active.Create) {
160
// Default to generic implementation, works with all mutex implementations
161
const SDL_rwlock_impl_t *impl = &SDL_rwlock_impl_generic;
162
{
163
HMODULE kernel32 = GetModuleHandle(TEXT("kernel32.dll"));
164
if (kernel32) {
165
bool okay = true;
166
#define LOOKUP_SRW_SYM(sym) if (okay) { if ((p##sym = (pfn##sym)GetProcAddress(kernel32, #sym)) == NULL) { okay = false; } }
167
LOOKUP_SRW_SYM(InitializeSRWLock);
168
LOOKUP_SRW_SYM(ReleaseSRWLockShared);
169
LOOKUP_SRW_SYM(AcquireSRWLockShared);
170
LOOKUP_SRW_SYM(TryAcquireSRWLockShared);
171
LOOKUP_SRW_SYM(ReleaseSRWLockExclusive);
172
LOOKUP_SRW_SYM(AcquireSRWLockExclusive);
173
LOOKUP_SRW_SYM(TryAcquireSRWLockExclusive);
174
#undef LOOKUP_SRW_SYM
175
if (okay) {
176
impl = &SDL_rwlock_impl_srw; // Use the Windows provided API instead of generic fallback
177
}
178
}
179
}
180
181
SDL_copyp(&SDL_rwlock_impl_active, impl);
182
}
183
return SDL_rwlock_impl_active.Create();
184
}
185
186
void SDL_DestroyRWLock(SDL_RWLock *rwlock)
187
{
188
if (rwlock) {
189
SDL_rwlock_impl_active.Destroy(rwlock);
190
}
191
}
192
193
void SDL_LockRWLockForReading(SDL_RWLock *rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS // clang doesn't know about NULL mutexes
194
{
195
if (rwlock) {
196
SDL_rwlock_impl_active.LockForReading(rwlock);
197
}
198
}
199
200
void SDL_LockRWLockForWriting(SDL_RWLock *rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS // clang doesn't know about NULL mutexes
201
{
202
if (rwlock) {
203
SDL_rwlock_impl_active.LockForWriting(rwlock);
204
}
205
}
206
207
bool SDL_TryLockRWLockForReading(SDL_RWLock *rwlock)
208
{
209
bool result = true;
210
if (rwlock) {
211
result = SDL_rwlock_impl_active.TryLockForReading(rwlock);
212
}
213
return result;
214
}
215
216
bool SDL_TryLockRWLockForWriting(SDL_RWLock *rwlock)
217
{
218
bool result = true;
219
if (rwlock) {
220
result = SDL_rwlock_impl_active.TryLockForWriting(rwlock);
221
}
222
return result;
223
}
224
225
void SDL_UnlockRWLock(SDL_RWLock *rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS // clang doesn't know about NULL mutexes
226
{
227
if (rwlock) {
228
SDL_rwlock_impl_active.Unlock(rwlock);
229
}
230
}
231
232
233