summaryrefslogtreecommitdiff
path: root/contrib/SDL-3.2.8/src/thread/windows/SDL_sysmutex.c
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2025-12-27 12:03:39 -0800
committer3gg <3gg@shellblade.net>2025-12-27 12:03:39 -0800
commit5a079a2d114f96d4847d1ee305d5b7c16eeec50e (patch)
tree8926ab44f168acf787d8e19608857b3af0f82758 /contrib/SDL-3.2.8/src/thread/windows/SDL_sysmutex.c
Initial commit
Diffstat (limited to 'contrib/SDL-3.2.8/src/thread/windows/SDL_sysmutex.c')
-rw-r--r--contrib/SDL-3.2.8/src/thread/windows/SDL_sysmutex.c238
1 files changed, 238 insertions, 0 deletions
diff --git a/contrib/SDL-3.2.8/src/thread/windows/SDL_sysmutex.c b/contrib/SDL-3.2.8/src/thread/windows/SDL_sysmutex.c
new file mode 100644
index 0000000..88ec004
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/thread/windows/SDL_sysmutex.c
@@ -0,0 +1,238 @@
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#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
36SDL_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
42typedef VOID(WINAPI *pfnInitializeSRWLock)(PSRWLOCK);
43typedef VOID(WINAPI *pfnReleaseSRWLockExclusive)(PSRWLOCK);
44typedef VOID(WINAPI *pfnAcquireSRWLockExclusive)(PSRWLOCK);
45typedef BOOLEAN(WINAPI *pfnTryAcquireSRWLockExclusive)(PSRWLOCK);
46static pfnInitializeSRWLock pInitializeSRWLock = NULL;
47static pfnReleaseSRWLockExclusive pReleaseSRWLockExclusive = NULL;
48static pfnAcquireSRWLockExclusive pAcquireSRWLockExclusive = NULL;
49static pfnTryAcquireSRWLockExclusive pTryAcquireSRWLockExclusive = NULL;
50
51static 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
60static void SDL_DestroyMutex_srw(SDL_Mutex *mutex)
61{
62 // There are no kernel allocated resources
63 SDL_free(mutex);
64}
65
66static 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
85static 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
105static 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
119static 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
132static 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
144static 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
151static 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
157static 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
163static 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
169static 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
182SDL_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
207void SDL_DestroyMutex(SDL_Mutex *mutex)
208{
209 if (mutex) {
210 SDL_mutex_impl_active.Destroy(mutex);
211 }
212}
213
214void SDL_LockMutex(SDL_Mutex *mutex)
215{
216 if (mutex) {
217 SDL_mutex_impl_active.Lock(mutex);
218 }
219}
220
221bool 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
231void SDL_UnlockMutex(SDL_Mutex *mutex)
232{
233 if (mutex) {
234 SDL_mutex_impl_active.Unlock(mutex);
235 }
236}
237
238#endif // SDL_THREAD_WINDOWS