Path: blob/master/thirdparty/sdl/thread/windows/SDL_sysmutex.c
9905 views
/*1Simple DirectMedia Layer2Copyright (C) 1997-2025 Sam Lantinga <[email protected]>34This software is provided 'as-is', without any express or implied5warranty. In no event will the authors be held liable for any damages6arising from the use of this software.78Permission is granted to anyone to use this software for any purpose,9including commercial applications, and to alter it and redistribute it10freely, subject to the following restrictions:11121. The origin of this software must not be misrepresented; you must not13claim that you wrote the original software. If you use this software14in a product, an acknowledgment in the product documentation would be15appreciated but is not required.162. Altered source versions must be plainly marked as such, and must not be17misrepresented as being the original software.183. This notice may not be removed or altered from any source distribution.19*/20#include "SDL_internal.h"2122#ifdef SDL_THREAD_WINDOWS2324/**25* Mutex functions using the Win32 API26* There are two implementations available based on:27* - Critical Sections. Available on all OS versions since Windows XP.28* - Slim Reader/Writer Locks. Requires Windows 7 or newer.29* which are chosen at runtime.30*/3132#include "SDL_sysmutex_c.h"3334// Implementation will be chosen at runtime based on available Kernel features35SDL_mutex_impl_t SDL_mutex_impl_active = { 0 };3637/**38* Implementation based on Slim Reader/Writer (SRW) Locks for Win 7 and newer.39*/4041typedef VOID(WINAPI *pfnInitializeSRWLock)(PSRWLOCK);42typedef VOID(WINAPI *pfnReleaseSRWLockExclusive)(PSRWLOCK);43typedef VOID(WINAPI *pfnAcquireSRWLockExclusive)(PSRWLOCK);44typedef BOOLEAN(WINAPI *pfnTryAcquireSRWLockExclusive)(PSRWLOCK);45static pfnInitializeSRWLock pInitializeSRWLock = NULL;46static pfnReleaseSRWLockExclusive pReleaseSRWLockExclusive = NULL;47static pfnAcquireSRWLockExclusive pAcquireSRWLockExclusive = NULL;48static pfnTryAcquireSRWLockExclusive pTryAcquireSRWLockExclusive = NULL;4950static SDL_Mutex *SDL_CreateMutex_srw(void)51{52SDL_mutex_srw *mutex = (SDL_mutex_srw *)SDL_calloc(1, sizeof(*mutex));53if (mutex) {54pInitializeSRWLock(&mutex->srw);55}56return (SDL_Mutex *)mutex;57}5859static void SDL_DestroyMutex_srw(SDL_Mutex *mutex)60{61// There are no kernel allocated resources62SDL_free(mutex);63}6465static void SDL_LockMutex_srw(SDL_Mutex *_mutex) SDL_NO_THREAD_SAFETY_ANALYSIS // clang doesn't know about NULL mutexes66{67SDL_mutex_srw *mutex = (SDL_mutex_srw *)_mutex;68const DWORD this_thread = GetCurrentThreadId();6970if (mutex->owner == this_thread) {71++mutex->count;72} else {73/* The order of operations is important.74We set the locking thread id after we obtain the lock75so unlocks from other threads will fail.76*/77pAcquireSRWLockExclusive(&mutex->srw);78SDL_assert(mutex->count == 0 && mutex->owner == 0);79mutex->owner = this_thread;80mutex->count = 1;81}82}8384static bool SDL_TryLockMutex_srw(SDL_Mutex *_mutex)85{86SDL_mutex_srw *mutex = (SDL_mutex_srw *)_mutex;87const DWORD this_thread = GetCurrentThreadId();88bool retval = true;8990if (mutex->owner == this_thread) {91++mutex->count;92} else {93if (pTryAcquireSRWLockExclusive(&mutex->srw) != 0) {94SDL_assert(mutex->count == 0 && mutex->owner == 0);95mutex->owner = this_thread;96mutex->count = 1;97} else {98retval = false;99}100}101return retval;102}103104static void SDL_UnlockMutex_srw(SDL_Mutex *_mutex) SDL_NO_THREAD_SAFETY_ANALYSIS // clang doesn't know about NULL mutexes105{106SDL_mutex_srw *mutex = (SDL_mutex_srw *)_mutex;107108if (mutex->owner == GetCurrentThreadId()) {109if (--mutex->count == 0) {110mutex->owner = 0;111pReleaseSRWLockExclusive(&mutex->srw);112}113} else {114SDL_assert(!"mutex not owned by this thread"); // undefined behavior...!115}116}117118static const SDL_mutex_impl_t SDL_mutex_impl_srw = {119&SDL_CreateMutex_srw,120&SDL_DestroyMutex_srw,121&SDL_LockMutex_srw,122&SDL_TryLockMutex_srw,123&SDL_UnlockMutex_srw,124SDL_MUTEX_SRW,125};126127/**128* Fallback Mutex implementation using Critical Sections (before Win 7)129*/130131static SDL_Mutex *SDL_CreateMutex_cs(void)132{133SDL_mutex_cs *mutex = (SDL_mutex_cs *)SDL_malloc(sizeof(*mutex));134if (mutex) {135// Initialize136// On SMP systems, a non-zero spin count generally helps performance137// This function always succeeds138(void)InitializeCriticalSectionAndSpinCount(&mutex->cs, 2000);139}140return (SDL_Mutex *)mutex;141}142143static void SDL_DestroyMutex_cs(SDL_Mutex *mutex_)144{145SDL_mutex_cs *mutex = (SDL_mutex_cs *)mutex_;146DeleteCriticalSection(&mutex->cs);147SDL_free(mutex);148}149150static void SDL_LockMutex_cs(SDL_Mutex *mutex_) SDL_NO_THREAD_SAFETY_ANALYSIS // clang doesn't know about NULL mutexes151{152SDL_mutex_cs *mutex = (SDL_mutex_cs *)mutex_;153EnterCriticalSection(&mutex->cs);154}155156static bool SDL_TryLockMutex_cs(SDL_Mutex *mutex_)157{158SDL_mutex_cs *mutex = (SDL_mutex_cs *)mutex_;159return (TryEnterCriticalSection(&mutex->cs) == TRUE);160}161162static void SDL_UnlockMutex_cs(SDL_Mutex *mutex_) SDL_NO_THREAD_SAFETY_ANALYSIS // clang doesn't know about NULL mutexes163{164SDL_mutex_cs *mutex = (SDL_mutex_cs *)mutex_;165LeaveCriticalSection(&mutex->cs);166}167168static const SDL_mutex_impl_t SDL_mutex_impl_cs = {169&SDL_CreateMutex_cs,170&SDL_DestroyMutex_cs,171&SDL_LockMutex_cs,172&SDL_TryLockMutex_cs,173&SDL_UnlockMutex_cs,174SDL_MUTEX_CS,175};176177/**178* Runtime selection and redirection179*/180181SDL_Mutex *SDL_CreateMutex(void)182{183if (!SDL_mutex_impl_active.Create) {184const SDL_mutex_impl_t *impl = &SDL_mutex_impl_cs;185186// Try faster implementation for Windows 7 and newer187HMODULE kernel32 = GetModuleHandle(TEXT("kernel32.dll"));188if (kernel32) {189// Requires Vista:190pInitializeSRWLock = (pfnInitializeSRWLock)GetProcAddress(kernel32, "InitializeSRWLock");191pReleaseSRWLockExclusive = (pfnReleaseSRWLockExclusive)GetProcAddress(kernel32, "ReleaseSRWLockExclusive");192pAcquireSRWLockExclusive = (pfnAcquireSRWLockExclusive)GetProcAddress(kernel32, "AcquireSRWLockExclusive");193// Requires 7:194pTryAcquireSRWLockExclusive = (pfnTryAcquireSRWLockExclusive)GetProcAddress(kernel32, "TryAcquireSRWLockExclusive");195if (pInitializeSRWLock && pReleaseSRWLockExclusive && pAcquireSRWLockExclusive && pTryAcquireSRWLockExclusive) {196impl = &SDL_mutex_impl_srw;197}198}199200// Copy instead of using pointer to save one level of indirection201SDL_copyp(&SDL_mutex_impl_active, impl);202}203return SDL_mutex_impl_active.Create();204}205206void SDL_DestroyMutex(SDL_Mutex *mutex)207{208if (mutex) {209SDL_mutex_impl_active.Destroy(mutex);210}211}212213void SDL_LockMutex(SDL_Mutex *mutex)214{215if (mutex) {216SDL_mutex_impl_active.Lock(mutex);217}218}219220bool SDL_TryLockMutex(SDL_Mutex *mutex)221{222bool result = true;223224if (mutex) {225result = SDL_mutex_impl_active.TryLock(mutex);226}227return result;228}229230void SDL_UnlockMutex(SDL_Mutex *mutex)231{232if (mutex) {233SDL_mutex_impl_active.Unlock(mutex);234}235}236237#endif // SDL_THREAD_WINDOWS238239240