summaryrefslogtreecommitdiff
path: root/contrib/SDL-3.2.8/src/thread/windows/SDL_sysrwlock_srw.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/SDL-3.2.8/src/thread/windows/SDL_sysrwlock_srw.c')
-rw-r--r--contrib/SDL-3.2.8/src/thread/windows/SDL_sysrwlock_srw.c231
1 files changed, 231 insertions, 0 deletions
diff --git a/contrib/SDL-3.2.8/src/thread/windows/SDL_sysrwlock_srw.c b/contrib/SDL-3.2.8/src/thread/windows/SDL_sysrwlock_srw.c
new file mode 100644
index 0000000..ca1a48e
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/thread/windows/SDL_sysrwlock_srw.c
@@ -0,0 +1,231 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
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
30typedef VOID(WINAPI *pfnInitializeSRWLock)(PSRWLOCK);
31typedef VOID(WINAPI *pfnReleaseSRWLockShared)(PSRWLOCK);
32typedef VOID(WINAPI *pfnAcquireSRWLockShared)(PSRWLOCK);
33typedef BOOLEAN(WINAPI *pfnTryAcquireSRWLockShared)(PSRWLOCK);
34typedef VOID(WINAPI *pfnReleaseSRWLockExclusive)(PSRWLOCK);
35typedef VOID(WINAPI *pfnAcquireSRWLockExclusive)(PSRWLOCK);
36typedef BOOLEAN(WINAPI *pfnTryAcquireSRWLockExclusive)(PSRWLOCK);
37
38static pfnInitializeSRWLock pInitializeSRWLock = NULL;
39static pfnReleaseSRWLockShared pReleaseSRWLockShared = NULL;
40static pfnAcquireSRWLockShared pAcquireSRWLockShared = NULL;
41static pfnTryAcquireSRWLockShared pTryAcquireSRWLockShared = NULL;
42static pfnReleaseSRWLockExclusive pReleaseSRWLockExclusive = NULL;
43static pfnAcquireSRWLockExclusive pAcquireSRWLockExclusive = NULL;
44static pfnTryAcquireSRWLockExclusive pTryAcquireSRWLockExclusive = NULL;
45
46typedef SDL_RWLock *(*pfnSDL_CreateRWLock)(void);
47typedef void (*pfnSDL_DestroyRWLock)(SDL_RWLock *);
48typedef void (*pfnSDL_LockRWLockForReading)(SDL_RWLock *);
49typedef void (*pfnSDL_LockRWLockForWriting)(SDL_RWLock *);
50typedef bool (*pfnSDL_TryLockRWLockForReading)(SDL_RWLock *);
51typedef bool (*pfnSDL_TryLockRWLockForWriting)(SDL_RWLock *);
52typedef void (*pfnSDL_UnlockRWLock)(SDL_RWLock *);
53
54typedef 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
66static SDL_rwlock_impl_t SDL_rwlock_impl_active = { 0 };
67
68// rwlock implementation using Win7+ slim read/write locks (SRWLOCK)
69
70typedef struct SDL_rwlock_srw
71{
72 SRWLOCK srw;
73 SDL_ThreadID write_owner;
74} SDL_rwlock_srw;
75
76static 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
85static 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
92static 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
98static 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
105static bool SDL_TryLockRWLockForReading_srw(SDL_RWLock *_rwlock)
106{
107 SDL_rwlock_srw *rwlock = (SDL_rwlock_srw *) _rwlock;
108 return pTryAcquireSRWLockShared(&rwlock->srw);
109}
110
111static 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
122static 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
133static 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
147static 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
157SDL_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
186void SDL_DestroyRWLock(SDL_RWLock *rwlock)
187{
188 if (rwlock) {
189 SDL_rwlock_impl_active.Destroy(rwlock);
190 }
191}
192
193void 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
200void 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
207bool 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
216bool 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
225void 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