Path: blob/master/thirdparty/sdl/thread/windows/SDL_sysrwlock_srw.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/**23* Implementation based on Slim Reader/Writer (SRW) Locks for Win 7 and newer.24*/2526// This header makes sure SRWLOCK is actually declared, even on ancient WinSDKs.27#include "SDL_sysmutex_c.h"2829typedef VOID(WINAPI *pfnInitializeSRWLock)(PSRWLOCK);30typedef VOID(WINAPI *pfnReleaseSRWLockShared)(PSRWLOCK);31typedef VOID(WINAPI *pfnAcquireSRWLockShared)(PSRWLOCK);32typedef BOOLEAN(WINAPI *pfnTryAcquireSRWLockShared)(PSRWLOCK);33typedef VOID(WINAPI *pfnReleaseSRWLockExclusive)(PSRWLOCK);34typedef VOID(WINAPI *pfnAcquireSRWLockExclusive)(PSRWLOCK);35typedef BOOLEAN(WINAPI *pfnTryAcquireSRWLockExclusive)(PSRWLOCK);3637static pfnInitializeSRWLock pInitializeSRWLock = NULL;38static pfnReleaseSRWLockShared pReleaseSRWLockShared = NULL;39static pfnAcquireSRWLockShared pAcquireSRWLockShared = NULL;40static pfnTryAcquireSRWLockShared pTryAcquireSRWLockShared = NULL;41static pfnReleaseSRWLockExclusive pReleaseSRWLockExclusive = NULL;42static pfnAcquireSRWLockExclusive pAcquireSRWLockExclusive = NULL;43static pfnTryAcquireSRWLockExclusive pTryAcquireSRWLockExclusive = NULL;4445typedef SDL_RWLock *(*pfnSDL_CreateRWLock)(void);46typedef void (*pfnSDL_DestroyRWLock)(SDL_RWLock *);47typedef void (*pfnSDL_LockRWLockForReading)(SDL_RWLock *);48typedef void (*pfnSDL_LockRWLockForWriting)(SDL_RWLock *);49typedef bool (*pfnSDL_TryLockRWLockForReading)(SDL_RWLock *);50typedef bool (*pfnSDL_TryLockRWLockForWriting)(SDL_RWLock *);51typedef void (*pfnSDL_UnlockRWLock)(SDL_RWLock *);5253typedef struct SDL_rwlock_impl_t54{55pfnSDL_CreateRWLock Create;56pfnSDL_DestroyRWLock Destroy;57pfnSDL_LockRWLockForReading LockForReading;58pfnSDL_LockRWLockForWriting LockForWriting;59pfnSDL_TryLockRWLockForReading TryLockForReading;60pfnSDL_TryLockRWLockForWriting TryLockForWriting;61pfnSDL_UnlockRWLock Unlock;62} SDL_rwlock_impl_t;6364// Implementation will be chosen at runtime based on available Kernel features65static SDL_rwlock_impl_t SDL_rwlock_impl_active = { 0 };6667// rwlock implementation using Win7+ slim read/write locks (SRWLOCK)6869typedef struct SDL_rwlock_srw70{71SRWLOCK srw;72SDL_ThreadID write_owner;73} SDL_rwlock_srw;7475static SDL_RWLock *SDL_CreateRWLock_srw(void)76{77SDL_rwlock_srw *rwlock = (SDL_rwlock_srw *)SDL_calloc(1, sizeof(*rwlock));78if (rwlock) {79pInitializeSRWLock(&rwlock->srw);80}81return (SDL_RWLock *)rwlock;82}8384static void SDL_DestroyRWLock_srw(SDL_RWLock *_rwlock)85{86SDL_rwlock_srw *rwlock = (SDL_rwlock_srw *) _rwlock;87// There are no kernel allocated resources88SDL_free(rwlock);89}9091static void SDL_LockRWLockForReading_srw(SDL_RWLock *_rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS // clang doesn't know about NULL mutexes92{93SDL_rwlock_srw *rwlock = (SDL_rwlock_srw *) _rwlock;94pAcquireSRWLockShared(&rwlock->srw);95}9697static void SDL_LockRWLockForWriting_srw(SDL_RWLock *_rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS // clang doesn't know about NULL mutexes98{99SDL_rwlock_srw *rwlock = (SDL_rwlock_srw *) _rwlock;100pAcquireSRWLockExclusive(&rwlock->srw);101rwlock->write_owner = SDL_GetCurrentThreadID();102}103104static bool SDL_TryLockRWLockForReading_srw(SDL_RWLock *_rwlock)105{106SDL_rwlock_srw *rwlock = (SDL_rwlock_srw *) _rwlock;107return pTryAcquireSRWLockShared(&rwlock->srw);108}109110static bool SDL_TryLockRWLockForWriting_srw(SDL_RWLock *_rwlock)111{112SDL_rwlock_srw *rwlock = (SDL_rwlock_srw *) _rwlock;113if (pTryAcquireSRWLockExclusive(&rwlock->srw)) {114rwlock->write_owner = SDL_GetCurrentThreadID();115return true;116} else {117return false;118}119}120121static void SDL_UnlockRWLock_srw(SDL_RWLock *_rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS // clang doesn't know about NULL mutexes122{123SDL_rwlock_srw *rwlock = (SDL_rwlock_srw *) _rwlock;124if (rwlock->write_owner == SDL_GetCurrentThreadID()) {125rwlock->write_owner = 0;126pReleaseSRWLockExclusive(&rwlock->srw);127} else {128pReleaseSRWLockShared(&rwlock->srw);129}130}131132static const SDL_rwlock_impl_t SDL_rwlock_impl_srw = {133&SDL_CreateRWLock_srw,134&SDL_DestroyRWLock_srw,135&SDL_LockRWLockForReading_srw,136&SDL_LockRWLockForWriting_srw,137&SDL_TryLockRWLockForReading_srw,138&SDL_TryLockRWLockForWriting_srw,139&SDL_UnlockRWLock_srw140};141142143#include "../generic/SDL_sysrwlock_c.h"144145// Generic rwlock implementation using SDL_Mutex, SDL_Condition, and SDL_AtomicInt146static const SDL_rwlock_impl_t SDL_rwlock_impl_generic = {147&SDL_CreateRWLock_generic,148&SDL_DestroyRWLock_generic,149&SDL_LockRWLockForReading_generic,150&SDL_LockRWLockForWriting_generic,151&SDL_TryLockRWLockForReading_generic,152&SDL_TryLockRWLockForWriting_generic,153&SDL_UnlockRWLock_generic154};155156SDL_RWLock *SDL_CreateRWLock(void)157{158if (!SDL_rwlock_impl_active.Create) {159// Default to generic implementation, works with all mutex implementations160const SDL_rwlock_impl_t *impl = &SDL_rwlock_impl_generic;161{162HMODULE kernel32 = GetModuleHandle(TEXT("kernel32.dll"));163if (kernel32) {164bool okay = true;165#define LOOKUP_SRW_SYM(sym) if (okay) { if ((p##sym = (pfn##sym)GetProcAddress(kernel32, #sym)) == NULL) { okay = false; } }166LOOKUP_SRW_SYM(InitializeSRWLock);167LOOKUP_SRW_SYM(ReleaseSRWLockShared);168LOOKUP_SRW_SYM(AcquireSRWLockShared);169LOOKUP_SRW_SYM(TryAcquireSRWLockShared);170LOOKUP_SRW_SYM(ReleaseSRWLockExclusive);171LOOKUP_SRW_SYM(AcquireSRWLockExclusive);172LOOKUP_SRW_SYM(TryAcquireSRWLockExclusive);173#undef LOOKUP_SRW_SYM174if (okay) {175impl = &SDL_rwlock_impl_srw; // Use the Windows provided API instead of generic fallback176}177}178}179180SDL_copyp(&SDL_rwlock_impl_active, impl);181}182return SDL_rwlock_impl_active.Create();183}184185void SDL_DestroyRWLock(SDL_RWLock *rwlock)186{187if (rwlock) {188SDL_rwlock_impl_active.Destroy(rwlock);189}190}191192void SDL_LockRWLockForReading(SDL_RWLock *rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS // clang doesn't know about NULL mutexes193{194if (rwlock) {195SDL_rwlock_impl_active.LockForReading(rwlock);196}197}198199void SDL_LockRWLockForWriting(SDL_RWLock *rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS // clang doesn't know about NULL mutexes200{201if (rwlock) {202SDL_rwlock_impl_active.LockForWriting(rwlock);203}204}205206bool SDL_TryLockRWLockForReading(SDL_RWLock *rwlock)207{208bool result = true;209if (rwlock) {210result = SDL_rwlock_impl_active.TryLockForReading(rwlock);211}212return result;213}214215bool SDL_TryLockRWLockForWriting(SDL_RWLock *rwlock)216{217bool result = true;218if (rwlock) {219result = SDL_rwlock_impl_active.TryLockForWriting(rwlock);220}221return result;222}223224void SDL_UnlockRWLock(SDL_RWLock *rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS // clang doesn't know about NULL mutexes225{226if (rwlock) {227SDL_rwlock_impl_active.Unlock(rwlock);228}229}230231232233