rwlock: Added SDL_rwlock API for shared locks.
parent
776820526b
commit
e474047ff8
|
@ -2008,11 +2008,14 @@ elseif(WINDOWS)
|
||||||
|
|
||||||
if(SDL_THREADS)
|
if(SDL_THREADS)
|
||||||
set(SDL_THREAD_GENERIC_COND_SUFFIX 1)
|
set(SDL_THREAD_GENERIC_COND_SUFFIX 1)
|
||||||
|
set(SDL_THREAD_GENERIC_RWLOCK_SUFFIX 1)
|
||||||
set(SDL_THREAD_WINDOWS 1)
|
set(SDL_THREAD_WINDOWS 1)
|
||||||
list(APPEND SOURCE_FILES
|
list(APPEND SOURCE_FILES
|
||||||
${SDL3_SOURCE_DIR}/src/thread/generic/SDL_syscond.c
|
${SDL3_SOURCE_DIR}/src/thread/generic/SDL_syscond.c
|
||||||
|
${SDL3_SOURCE_DIR}/src/thread/generic/SDL_sysrwlock.c
|
||||||
${SDL3_SOURCE_DIR}/src/thread/windows/SDL_syscond_cv.c
|
${SDL3_SOURCE_DIR}/src/thread/windows/SDL_syscond_cv.c
|
||||||
${SDL3_SOURCE_DIR}/src/thread/windows/SDL_sysmutex.c
|
${SDL3_SOURCE_DIR}/src/thread/windows/SDL_sysmutex.c
|
||||||
|
${SDL3_SOURCE_DIR}/src/thread/windows/SDL_sysrwlock_srw.c
|
||||||
${SDL3_SOURCE_DIR}/src/thread/windows/SDL_syssem.c
|
${SDL3_SOURCE_DIR}/src/thread/windows/SDL_syssem.c
|
||||||
${SDL3_SOURCE_DIR}/src/thread/windows/SDL_systhread.c
|
${SDL3_SOURCE_DIR}/src/thread/windows/SDL_systhread.c
|
||||||
${SDL3_SOURCE_DIR}/src/thread/windows/SDL_systls.c)
|
${SDL3_SOURCE_DIR}/src/thread/windows/SDL_systls.c)
|
||||||
|
@ -2597,6 +2600,7 @@ elseif(VITA)
|
||||||
${SDL3_SOURCE_DIR}/src/thread/vita/SDL_syssem.c
|
${SDL3_SOURCE_DIR}/src/thread/vita/SDL_syssem.c
|
||||||
${SDL3_SOURCE_DIR}/src/thread/vita/SDL_systhread.c
|
${SDL3_SOURCE_DIR}/src/thread/vita/SDL_systhread.c
|
||||||
${SDL3_SOURCE_DIR}/src/thread/vita/SDL_syscond.c
|
${SDL3_SOURCE_DIR}/src/thread/vita/SDL_syscond.c
|
||||||
|
${SDL3_SOURCE_DIR}/src/thread/generic/SDL_sysrwlock.c
|
||||||
${SDL3_SOURCE_DIR}/src/thread/generic/SDL_systls.c)
|
${SDL3_SOURCE_DIR}/src/thread/generic/SDL_systls.c)
|
||||||
set(HAVE_SDL_THREADS TRUE)
|
set(HAVE_SDL_THREADS TRUE)
|
||||||
endif()
|
endif()
|
||||||
|
@ -2732,7 +2736,7 @@ elseif(PSP)
|
||||||
endif()
|
endif()
|
||||||
if(SDL_THREADS)
|
if(SDL_THREADS)
|
||||||
set(SDL_THREAD_PSP 1)
|
set(SDL_THREAD_PSP 1)
|
||||||
file(GLOB PSP_THREAD_SOURCES ${SDL3_SOURCE_DIR}/src/thread/generic/SDL_systls.c ${SDL3_SOURCE_DIR}/src/thread/psp/*.c)
|
file(GLOB PSP_THREAD_SOURCES ${SDL3_SOURCE_DIR}/src/thread/generic/SDL_systls.c ${SDL3_SOURCE_DIR}/src/thread/generic/SDL_sysrwlock.c ${SDL3_SOURCE_DIR}/src/thread/psp/*.c)
|
||||||
list(APPEND SOURCE_FILES ${PSP_THREAD_SOURCES})
|
list(APPEND SOURCE_FILES ${PSP_THREAD_SOURCES})
|
||||||
set(HAVE_SDL_THREADS TRUE)
|
set(HAVE_SDL_THREADS TRUE)
|
||||||
endif()
|
endif()
|
||||||
|
@ -2791,7 +2795,7 @@ elseif(PS2)
|
||||||
endif()
|
endif()
|
||||||
if(SDL_THREADS)
|
if(SDL_THREADS)
|
||||||
set(SDL_THREAD_PS2 1)
|
set(SDL_THREAD_PS2 1)
|
||||||
file(GLOB PS2_THREAD_SOURCES ${SDL3_SOURCE_DIR}/src/thread/generic/SDL_syscond.c ${SDL3_SOURCE_DIR}/src/thread/generic/SDL_sysmutex.c ${SDL3_SOURCE_DIR}/src/thread/generic/SDL_systls.c ${SDL3_SOURCE_DIR}/src/thread/ps2/*.c)
|
file(GLOB PS2_THREAD_SOURCES ${SDL3_SOURCE_DIR}/src/thread/generic/SDL_syscond.c ${SDL3_SOURCE_DIR}/src/thread/generic/SDL_sysmutex.c ${SDL3_SOURCE_DIR}/src/thread/generic/SDL_sysrwlock.c ${SDL3_SOURCE_DIR}/src/thread/generic/SDL_systls.c ${SDL3_SOURCE_DIR}/src/thread/ps2/*.c)
|
||||||
list(APPEND SOURCE_FILES ${PS2_THREAD_SOURCES})
|
list(APPEND SOURCE_FILES ${PS2_THREAD_SOURCES})
|
||||||
set(HAVE_SDL_THREADS TRUE)
|
set(HAVE_SDL_THREADS TRUE)
|
||||||
endif()
|
endif()
|
||||||
|
@ -2852,7 +2856,7 @@ elseif(N3DS)
|
||||||
if(SDL_THREADS)
|
if(SDL_THREADS)
|
||||||
set(SDL_THREAD_N3DS 1)
|
set(SDL_THREAD_N3DS 1)
|
||||||
file(GLOB N3DS_THREAD_SOURCES ${SDL3_SOURCE_DIR}/src/thread/n3ds/*.c)
|
file(GLOB N3DS_THREAD_SOURCES ${SDL3_SOURCE_DIR}/src/thread/n3ds/*.c)
|
||||||
list(APPEND SOURCE_FILES ${N3DS_THREAD_SOURCES} ${SDL3_SOURCE_DIR}/src/thread/generic/SDL_systls.c)
|
list(APPEND SOURCE_FILES ${N3DS_THREAD_SOURCES} ${SDL3_SOURCE_DIR}/src/thread/generic/SDL_systls.c ${SDL3_SOURCE_DIR}/src/thread/generic/SDL_sysrwlock.c)
|
||||||
set(HAVE_SDL_THREADS TRUE)
|
set(HAVE_SDL_THREADS TRUE)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
@ -1225,6 +1225,9 @@
|
||||||
<ClCompile Include="..\..\src\thread\windows\SDL_sysmutex.c">
|
<ClCompile Include="..\..\src\thread\windows\SDL_sysmutex.c">
|
||||||
<Filter>thread\windows</Filter>
|
<Filter>thread\windows</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\thread\windows\SDL_sysrwlock_srw.c">
|
||||||
|
<Filter>thread\windows</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\thread\windows\SDL_syssem.c">
|
<ClCompile Include="..\..\src\thread\windows\SDL_syssem.c">
|
||||||
<Filter>thread\windows</Filter>
|
<Filter>thread\windows</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -1237,6 +1240,9 @@
|
||||||
<ClCompile Include="..\..\src\thread\generic\SDL_syscond.c">
|
<ClCompile Include="..\..\src\thread\generic\SDL_syscond.c">
|
||||||
<Filter>thread\generic</Filter>
|
<Filter>thread\generic</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\thread\generic\SDL_sysrwlock.c">
|
||||||
|
<Filter>thread\generic</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\stdlib\SDL_crc16.c">
|
<ClCompile Include="..\..\src\stdlib\SDL_crc16.c">
|
||||||
<Filter>stdlib</Filter>
|
<Filter>stdlib</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
|
|
@ -444,6 +444,24 @@
|
||||||
<CompileAsWinRT Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</CompileAsWinRT>
|
<CompileAsWinRT Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</CompileAsWinRT>
|
||||||
<CompileAsWinRT Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</CompileAsWinRT>
|
<CompileAsWinRT Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</CompileAsWinRT>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\src\thread\stdcpp\SDL_sysrwlock.cpp">
|
||||||
|
<PrecompiledHeaderOutputFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)$(TargetName)_cpp.pch</PrecompiledHeaderOutputFile>
|
||||||
|
<PrecompiledHeaderOutputFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)$(TargetName)_cpp.pch</PrecompiledHeaderOutputFile>
|
||||||
|
<PrecompiledHeaderOutputFile Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">$(IntDir)$(TargetName)_cpp.pch</PrecompiledHeaderOutputFile>
|
||||||
|
<PrecompiledHeaderOutputFile Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">$(IntDir)$(TargetName)_cpp.pch</PrecompiledHeaderOutputFile>
|
||||||
|
<PrecompiledHeaderOutputFile Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">$(IntDir)$(TargetName)_cpp.pch</PrecompiledHeaderOutputFile>
|
||||||
|
<PrecompiledHeaderOutputFile Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">$(IntDir)$(TargetName)_cpp.pch</PrecompiledHeaderOutputFile>
|
||||||
|
<PrecompiledHeaderOutputFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)$(TargetName)_cpp.pch</PrecompiledHeaderOutputFile>
|
||||||
|
<PrecompiledHeaderOutputFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)$(TargetName)_cpp.pch</PrecompiledHeaderOutputFile>
|
||||||
|
<CompileAsWinRT Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</CompileAsWinRT>
|
||||||
|
<CompileAsWinRT Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</CompileAsWinRT>
|
||||||
|
<CompileAsWinRT Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">true</CompileAsWinRT>
|
||||||
|
<CompileAsWinRT Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">true</CompileAsWinRT>
|
||||||
|
<CompileAsWinRT Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">true</CompileAsWinRT>
|
||||||
|
<CompileAsWinRT Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">true</CompileAsWinRT>
|
||||||
|
<CompileAsWinRT Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</CompileAsWinRT>
|
||||||
|
<CompileAsWinRT Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</CompileAsWinRT>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\src\thread\stdcpp\SDL_systhread.cpp">
|
<ClCompile Include="..\src\thread\stdcpp\SDL_systhread.cpp">
|
||||||
<PrecompiledHeaderOutputFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)$(TargetName)_cpp.pch</PrecompiledHeaderOutputFile>
|
<PrecompiledHeaderOutputFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)$(TargetName)_cpp.pch</PrecompiledHeaderOutputFile>
|
||||||
<PrecompiledHeaderOutputFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)$(TargetName)_cpp.pch</PrecompiledHeaderOutputFile>
|
<PrecompiledHeaderOutputFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)$(TargetName)_cpp.pch</PrecompiledHeaderOutputFile>
|
||||||
|
|
|
@ -678,6 +678,9 @@
|
||||||
<ClCompile Include="..\src\thread\stdcpp\SDL_sysmutex.cpp">
|
<ClCompile Include="..\src\thread\stdcpp\SDL_sysmutex.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\src\thread\stdcpp\SDL_sysrwlock.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\src\thread\stdcpp\SDL_systhread.cpp">
|
<ClCompile Include="..\src\thread\stdcpp\SDL_systhread.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
|
|
@ -402,6 +402,7 @@
|
||||||
<ClInclude Include="..\..\src\thread\SDL_thread_c.h" />
|
<ClInclude Include="..\..\src\thread\SDL_thread_c.h" />
|
||||||
<ClInclude Include="..\..\src\thread\generic\SDL_syscond_c.h" />
|
<ClInclude Include="..\..\src\thread\generic\SDL_syscond_c.h" />
|
||||||
<ClInclude Include="..\..\src\thread\windows\SDL_sysmutex_c.h" />
|
<ClInclude Include="..\..\src\thread\windows\SDL_sysmutex_c.h" />
|
||||||
|
<ClInclude Include="..\..\src\thread\generic\SDL_sysrwlock_c.h" />
|
||||||
<ClInclude Include="..\..\src\thread\windows\SDL_systhread_c.h" />
|
<ClInclude Include="..\..\src\thread\windows\SDL_systhread_c.h" />
|
||||||
<ClInclude Include="..\..\src\timer\SDL_timer_c.h" />
|
<ClInclude Include="..\..\src\timer\SDL_timer_c.h" />
|
||||||
<ClInclude Include="..\..\src\video\dummy\SDL_nullevents_c.h" />
|
<ClInclude Include="..\..\src\video\dummy\SDL_nullevents_c.h" />
|
||||||
|
@ -599,9 +600,11 @@
|
||||||
<ClCompile Include="..\..\src\stdlib\SDL_string.c" />
|
<ClCompile Include="..\..\src\stdlib\SDL_string.c" />
|
||||||
<ClCompile Include="..\..\src\stdlib\SDL_strtokr.c" />
|
<ClCompile Include="..\..\src\stdlib\SDL_strtokr.c" />
|
||||||
<ClCompile Include="..\..\src\thread\generic\SDL_syscond.c" />
|
<ClCompile Include="..\..\src\thread\generic\SDL_syscond.c" />
|
||||||
|
<ClCompile Include="..\..\src\thread\generic\SDL_sysrwlock.c" />
|
||||||
<ClCompile Include="..\..\src\thread\SDL_thread.c" />
|
<ClCompile Include="..\..\src\thread\SDL_thread.c" />
|
||||||
<ClCompile Include="..\..\src\thread\windows\SDL_syscond_cv.c" />
|
<ClCompile Include="..\..\src\thread\windows\SDL_syscond_cv.c" />
|
||||||
<ClCompile Include="..\..\src\thread\windows\SDL_sysmutex.c" />
|
<ClCompile Include="..\..\src\thread\windows\SDL_sysmutex.c" />
|
||||||
|
<ClCompile Include="..\..\src\thread\windows\SDL_sysrwlock_srw.c" />
|
||||||
<ClCompile Include="..\..\src\thread\windows\SDL_syssem.c" />
|
<ClCompile Include="..\..\src\thread\windows\SDL_syssem.c" />
|
||||||
<ClCompile Include="..\..\src\thread\windows\SDL_systhread.c" />
|
<ClCompile Include="..\..\src\thread\windows\SDL_systhread.c" />
|
||||||
<ClCompile Include="..\..\src\thread\windows\SDL_systls.c" />
|
<ClCompile Include="..\..\src\thread\windows\SDL_systls.c" />
|
||||||
|
|
|
@ -1213,6 +1213,9 @@
|
||||||
<ClCompile Include="..\..\src\thread\windows\SDL_sysmutex.c">
|
<ClCompile Include="..\..\src\thread\windows\SDL_sysmutex.c">
|
||||||
<Filter>thread\windows</Filter>
|
<Filter>thread\windows</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\thread\windows\SDL_sysrwlock_srw.c">
|
||||||
|
<Filter>thread\windows</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\thread\windows\SDL_syssem.c">
|
<ClCompile Include="..\..\src\thread\windows\SDL_syssem.c">
|
||||||
<Filter>thread\windows</Filter>
|
<Filter>thread\windows</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
|
|
@ -83,6 +83,15 @@
|
||||||
566E26CF246274CC00718109 /* SDL_syslocale.m in Sources */ = {isa = PBXBuildFile; fileRef = 566E26CC246274CB00718109 /* SDL_syslocale.m */; };
|
566E26CF246274CC00718109 /* SDL_syslocale.m in Sources */ = {isa = PBXBuildFile; fileRef = 566E26CC246274CB00718109 /* SDL_syslocale.m */; };
|
||||||
566E26D8246274CC00718109 /* SDL_locale.c in Sources */ = {isa = PBXBuildFile; fileRef = 566E26CD246274CB00718109 /* SDL_locale.c */; };
|
566E26D8246274CC00718109 /* SDL_locale.c in Sources */ = {isa = PBXBuildFile; fileRef = 566E26CD246274CB00718109 /* SDL_locale.c */; };
|
||||||
566E26E1246274CC00718109 /* SDL_syslocale.h in Headers */ = {isa = PBXBuildFile; fileRef = 566E26CE246274CC00718109 /* SDL_syslocale.h */; };
|
566E26E1246274CC00718109 /* SDL_syslocale.h in Headers */ = {isa = PBXBuildFile; fileRef = 566E26CE246274CC00718109 /* SDL_syslocale.h */; };
|
||||||
|
56A2373329F9C113003CCA5F /* SDL_sysrwlock.c in Sources */ = {isa = PBXBuildFile; fileRef = 56A2373229F9C113003CCA5F /* SDL_sysrwlock.c */; };
|
||||||
|
56A2373429F9C113003CCA5F /* SDL_sysrwlock.c in Sources */ = {isa = PBXBuildFile; fileRef = 56A2373229F9C113003CCA5F /* SDL_sysrwlock.c */; };
|
||||||
|
56A2373529F9C113003CCA5F /* SDL_sysrwlock.c in Sources */ = {isa = PBXBuildFile; fileRef = 56A2373229F9C113003CCA5F /* SDL_sysrwlock.c */; };
|
||||||
|
56A2373629F9C113003CCA5F /* SDL_sysrwlock.c in Sources */ = {isa = PBXBuildFile; fileRef = 56A2373229F9C113003CCA5F /* SDL_sysrwlock.c */; };
|
||||||
|
56A2373729F9C113003CCA5F /* SDL_sysrwlock.c in Sources */ = {isa = PBXBuildFile; fileRef = 56A2373229F9C113003CCA5F /* SDL_sysrwlock.c */; };
|
||||||
|
56A2373829F9C113003CCA5F /* SDL_sysrwlock.c in Sources */ = {isa = PBXBuildFile; fileRef = 56A2373229F9C113003CCA5F /* SDL_sysrwlock.c */; };
|
||||||
|
56A2373929F9C113003CCA5F /* SDL_sysrwlock.c in Sources */ = {isa = PBXBuildFile; fileRef = 56A2373229F9C113003CCA5F /* SDL_sysrwlock.c */; };
|
||||||
|
56A2373A29F9C113003CCA5F /* SDL_sysrwlock.c in Sources */ = {isa = PBXBuildFile; fileRef = 56A2373229F9C113003CCA5F /* SDL_sysrwlock.c */; };
|
||||||
|
56A2373B29F9C113003CCA5F /* SDL_sysrwlock.c in Sources */ = {isa = PBXBuildFile; fileRef = 56A2373229F9C113003CCA5F /* SDL_sysrwlock.c */; };
|
||||||
56C5237F1D8F4985001F2F30 /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A7381E951D8B69D600B177DD /* CoreAudio.framework */; };
|
56C5237F1D8F4985001F2F30 /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A7381E951D8B69D600B177DD /* CoreAudio.framework */; };
|
||||||
56C523811D8F498C001F2F30 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00D0D08310675DD9004B05EF /* CoreFoundation.framework */; };
|
56C523811D8F498C001F2F30 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00D0D08310675DD9004B05EF /* CoreFoundation.framework */; };
|
||||||
75E0915A241EA924004729E1 /* SDL_virtualjoystick.c in Sources */ = {isa = PBXBuildFile; fileRef = 75E09158241EA924004729E1 /* SDL_virtualjoystick.c */; };
|
75E0915A241EA924004729E1 /* SDL_virtualjoystick.c in Sources */ = {isa = PBXBuildFile; fileRef = 75E09158241EA924004729E1 /* SDL_virtualjoystick.c */; };
|
||||||
|
@ -3482,6 +3491,7 @@
|
||||||
566E26CC246274CB00718109 /* SDL_syslocale.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SDL_syslocale.m; path = locale/macos/SDL_syslocale.m; sourceTree = "<group>"; };
|
566E26CC246274CB00718109 /* SDL_syslocale.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SDL_syslocale.m; path = locale/macos/SDL_syslocale.m; sourceTree = "<group>"; };
|
||||||
566E26CD246274CB00718109 /* SDL_locale.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SDL_locale.c; path = locale/SDL_locale.c; sourceTree = "<group>"; };
|
566E26CD246274CB00718109 /* SDL_locale.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SDL_locale.c; path = locale/SDL_locale.c; sourceTree = "<group>"; };
|
||||||
566E26CE246274CC00718109 /* SDL_syslocale.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SDL_syslocale.h; path = locale/SDL_syslocale.h; sourceTree = "<group>"; };
|
566E26CE246274CC00718109 /* SDL_syslocale.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SDL_syslocale.h; path = locale/SDL_syslocale.h; sourceTree = "<group>"; };
|
||||||
|
56A2373229F9C113003CCA5F /* SDL_sysrwlock.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_sysrwlock.c; sourceTree = "<group>"; };
|
||||||
75E09158241EA924004729E1 /* SDL_virtualjoystick.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_virtualjoystick.c; sourceTree = "<group>"; };
|
75E09158241EA924004729E1 /* SDL_virtualjoystick.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_virtualjoystick.c; sourceTree = "<group>"; };
|
||||||
75E09159241EA924004729E1 /* SDL_virtualjoystick_c.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_virtualjoystick_c.h; sourceTree = "<group>"; };
|
75E09159241EA924004729E1 /* SDL_virtualjoystick_c.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_virtualjoystick_c.h; sourceTree = "<group>"; };
|
||||||
9846B07B287A9020000C35C8 /* SDL_hidapi_shield.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_hidapi_shield.c; sourceTree = "<group>"; };
|
9846B07B287A9020000C35C8 /* SDL_hidapi_shield.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_hidapi_shield.c; sourceTree = "<group>"; };
|
||||||
|
@ -4691,6 +4701,7 @@
|
||||||
A7D8A78123E2513E00DCD162 /* pthread */ = {
|
A7D8A78123E2513E00DCD162 /* pthread */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
56A2373229F9C113003CCA5F /* SDL_sysrwlock.c */,
|
||||||
A7D8A78523E2513E00DCD162 /* SDL_syscond.c */,
|
A7D8A78523E2513E00DCD162 /* SDL_syscond.c */,
|
||||||
A7D8A78823E2513E00DCD162 /* SDL_sysmutex_c.h */,
|
A7D8A78823E2513E00DCD162 /* SDL_sysmutex_c.h */,
|
||||||
A7D8A78723E2513E00DCD162 /* SDL_sysmutex.c */,
|
A7D8A78723E2513E00DCD162 /* SDL_sysmutex.c */,
|
||||||
|
@ -7328,6 +7339,7 @@
|
||||||
A75FCE7023E25AB700529352 /* SDL_hidapi_xboxone.c in Sources */,
|
A75FCE7023E25AB700529352 /* SDL_hidapi_xboxone.c in Sources */,
|
||||||
A75FCE7123E25AB700529352 /* SDL_blit_auto.c in Sources */,
|
A75FCE7123E25AB700529352 /* SDL_blit_auto.c in Sources */,
|
||||||
A75FCE7323E25AB700529352 /* SDL_keyboard.c in Sources */,
|
A75FCE7323E25AB700529352 /* SDL_keyboard.c in Sources */,
|
||||||
|
56A2373A29F9C113003CCA5F /* SDL_sysrwlock.c in Sources */,
|
||||||
A75FCE7523E25AB700529352 /* SDL_rect.c in Sources */,
|
A75FCE7523E25AB700529352 /* SDL_rect.c in Sources */,
|
||||||
A75FCE7623E25AB700529352 /* SDL_cocoaopengles.m in Sources */,
|
A75FCE7623E25AB700529352 /* SDL_cocoaopengles.m in Sources */,
|
||||||
A75FCE7723E25AB700529352 /* SDL_qsort.c in Sources */,
|
A75FCE7723E25AB700529352 /* SDL_qsort.c in Sources */,
|
||||||
|
@ -7523,6 +7535,7 @@
|
||||||
A75FD02923E25AC700529352 /* SDL_hidapi_xboxone.c in Sources */,
|
A75FD02923E25AC700529352 /* SDL_hidapi_xboxone.c in Sources */,
|
||||||
A75FD02A23E25AC700529352 /* SDL_blit_auto.c in Sources */,
|
A75FD02A23E25AC700529352 /* SDL_blit_auto.c in Sources */,
|
||||||
A75FD02C23E25AC700529352 /* SDL_keyboard.c in Sources */,
|
A75FD02C23E25AC700529352 /* SDL_keyboard.c in Sources */,
|
||||||
|
56A2373B29F9C113003CCA5F /* SDL_sysrwlock.c in Sources */,
|
||||||
A75FD02E23E25AC700529352 /* SDL_rect.c in Sources */,
|
A75FD02E23E25AC700529352 /* SDL_rect.c in Sources */,
|
||||||
A75FD02F23E25AC700529352 /* SDL_cocoaopengles.m in Sources */,
|
A75FD02F23E25AC700529352 /* SDL_cocoaopengles.m in Sources */,
|
||||||
A75FD03023E25AC700529352 /* SDL_qsort.c in Sources */,
|
A75FD03023E25AC700529352 /* SDL_qsort.c in Sources */,
|
||||||
|
@ -7718,6 +7731,7 @@
|
||||||
A769B20423E259AE00872273 /* SDL_hidapi_switch.c in Sources */,
|
A769B20423E259AE00872273 /* SDL_hidapi_switch.c in Sources */,
|
||||||
F3984CD525BCC92900374F43 /* SDL_hidapi_stadia.c in Sources */,
|
F3984CD525BCC92900374F43 /* SDL_hidapi_stadia.c in Sources */,
|
||||||
A769B20523E259AE00872273 /* SDL_strtokr.c in Sources */,
|
A769B20523E259AE00872273 /* SDL_strtokr.c in Sources */,
|
||||||
|
56A2373829F9C113003CCA5F /* SDL_sysrwlock.c in Sources */,
|
||||||
5605720B2473687A00B46B66 /* SDL_syslocale.m in Sources */,
|
5605720B2473687A00B46B66 /* SDL_syslocale.m in Sources */,
|
||||||
F3820718284F3609004DD584 /* controller_type.c in Sources */,
|
F3820718284F3609004DD584 /* controller_type.c in Sources */,
|
||||||
A769B20623E259AE00872273 /* SDL_clipboardevents.c in Sources */,
|
A769B20623E259AE00872273 /* SDL_clipboardevents.c in Sources */,
|
||||||
|
@ -7913,6 +7927,7 @@
|
||||||
A7D8BB6A23E2514500DCD162 /* SDL_keyboard.c in Sources */,
|
A7D8BB6A23E2514500DCD162 /* SDL_keyboard.c in Sources */,
|
||||||
A7D8ACE823E2514100DCD162 /* SDL_rect.c in Sources */,
|
A7D8ACE823E2514100DCD162 /* SDL_rect.c in Sources */,
|
||||||
A7D8AE9B23E2514100DCD162 /* SDL_cocoaopengles.m in Sources */,
|
A7D8AE9B23E2514100DCD162 /* SDL_cocoaopengles.m in Sources */,
|
||||||
|
56A2373429F9C113003CCA5F /* SDL_sysrwlock.c in Sources */,
|
||||||
A7D8B96923E2514400DCD162 /* SDL_qsort.c in Sources */,
|
A7D8B96923E2514400DCD162 /* SDL_qsort.c in Sources */,
|
||||||
A7D8B55223E2514300DCD162 /* SDL_hidapi_switch.c in Sources */,
|
A7D8B55223E2514300DCD162 /* SDL_hidapi_switch.c in Sources */,
|
||||||
A7D8B96323E2514400DCD162 /* SDL_strtokr.c in Sources */,
|
A7D8B96323E2514400DCD162 /* SDL_strtokr.c in Sources */,
|
||||||
|
@ -8108,6 +8123,7 @@
|
||||||
A7D8BB6B23E2514500DCD162 /* SDL_keyboard.c in Sources */,
|
A7D8BB6B23E2514500DCD162 /* SDL_keyboard.c in Sources */,
|
||||||
A7D8ACE923E2514100DCD162 /* SDL_rect.c in Sources */,
|
A7D8ACE923E2514100DCD162 /* SDL_rect.c in Sources */,
|
||||||
A7D8AE9C23E2514100DCD162 /* SDL_cocoaopengles.m in Sources */,
|
A7D8AE9C23E2514100DCD162 /* SDL_cocoaopengles.m in Sources */,
|
||||||
|
56A2373529F9C113003CCA5F /* SDL_sysrwlock.c in Sources */,
|
||||||
A7D8B96A23E2514400DCD162 /* SDL_qsort.c in Sources */,
|
A7D8B96A23E2514400DCD162 /* SDL_qsort.c in Sources */,
|
||||||
A7D8B55323E2514300DCD162 /* SDL_hidapi_switch.c in Sources */,
|
A7D8B55323E2514300DCD162 /* SDL_hidapi_switch.c in Sources */,
|
||||||
A7D8B96423E2514400DCD162 /* SDL_strtokr.c in Sources */,
|
A7D8B96423E2514400DCD162 /* SDL_strtokr.c in Sources */,
|
||||||
|
@ -8303,6 +8319,7 @@
|
||||||
A7D8B55523E2514300DCD162 /* SDL_hidapi_switch.c in Sources */,
|
A7D8B55523E2514300DCD162 /* SDL_hidapi_switch.c in Sources */,
|
||||||
F3984CD425BCC92900374F43 /* SDL_hidapi_stadia.c in Sources */,
|
F3984CD425BCC92900374F43 /* SDL_hidapi_stadia.c in Sources */,
|
||||||
A7D8B96623E2514400DCD162 /* SDL_strtokr.c in Sources */,
|
A7D8B96623E2514400DCD162 /* SDL_strtokr.c in Sources */,
|
||||||
|
56A2373729F9C113003CCA5F /* SDL_sysrwlock.c in Sources */,
|
||||||
560572092473687900B46B66 /* SDL_syslocale.m in Sources */,
|
560572092473687900B46B66 /* SDL_syslocale.m in Sources */,
|
||||||
F3820717284F3609004DD584 /* controller_type.c in Sources */,
|
F3820717284F3609004DD584 /* controller_type.c in Sources */,
|
||||||
A7D8BB7923E2514500DCD162 /* SDL_clipboardevents.c in Sources */,
|
A7D8BB7923E2514500DCD162 /* SDL_clipboardevents.c in Sources */,
|
||||||
|
@ -8469,6 +8486,7 @@
|
||||||
A7D8ADE623E2514100DCD162 /* SDL_blit_0.c in Sources */,
|
A7D8ADE623E2514100DCD162 /* SDL_blit_0.c in Sources */,
|
||||||
A7D8BB0923E2514500DCD162 /* k_tan.c in Sources */,
|
A7D8BB0923E2514500DCD162 /* k_tan.c in Sources */,
|
||||||
A7D8B8A823E2514400DCD162 /* SDL_diskaudio.c in Sources */,
|
A7D8B8A823E2514400DCD162 /* SDL_diskaudio.c in Sources */,
|
||||||
|
56A2373329F9C113003CCA5F /* SDL_sysrwlock.c in Sources */,
|
||||||
566E26CF246274CC00718109 /* SDL_syslocale.m in Sources */,
|
566E26CF246274CC00718109 /* SDL_syslocale.m in Sources */,
|
||||||
A7D8AFC023E2514200DCD162 /* SDL_egl.c in Sources */,
|
A7D8AFC023E2514200DCD162 /* SDL_egl.c in Sources */,
|
||||||
A7D8AC3323E2514100DCD162 /* SDL_RLEaccel.c in Sources */,
|
A7D8AC3323E2514100DCD162 /* SDL_RLEaccel.c in Sources */,
|
||||||
|
@ -8663,6 +8681,7 @@
|
||||||
A7D8BBF223E2574800DCD162 /* SDL_uikitevents.m in Sources */,
|
A7D8BBF223E2574800DCD162 /* SDL_uikitevents.m in Sources */,
|
||||||
A7D8BBB923E2560500DCD162 /* SDL_steamcontroller.c in Sources */,
|
A7D8BBB923E2560500DCD162 /* SDL_steamcontroller.c in Sources */,
|
||||||
A7D8B8AB23E2514400DCD162 /* SDL_diskaudio.c in Sources */,
|
A7D8B8AB23E2514400DCD162 /* SDL_diskaudio.c in Sources */,
|
||||||
|
56A2373629F9C113003CCA5F /* SDL_sysrwlock.c in Sources */,
|
||||||
A7D8AFC323E2514200DCD162 /* SDL_egl.c in Sources */,
|
A7D8AFC323E2514200DCD162 /* SDL_egl.c in Sources */,
|
||||||
A7D8AC3623E2514100DCD162 /* SDL_RLEaccel.c in Sources */,
|
A7D8AC3623E2514100DCD162 /* SDL_RLEaccel.c in Sources */,
|
||||||
A7D8BBB423E2514500DCD162 /* SDL_assert.c in Sources */,
|
A7D8BBB423E2514500DCD162 /* SDL_assert.c in Sources */,
|
||||||
|
@ -8857,6 +8876,7 @@
|
||||||
A7D8ADEB23E2514100DCD162 /* SDL_blit_0.c in Sources */,
|
A7D8ADEB23E2514100DCD162 /* SDL_blit_0.c in Sources */,
|
||||||
A7D8BB0E23E2514500DCD162 /* k_tan.c in Sources */,
|
A7D8BB0E23E2514500DCD162 /* k_tan.c in Sources */,
|
||||||
A7D8B8AD23E2514400DCD162 /* SDL_diskaudio.c in Sources */,
|
A7D8B8AD23E2514400DCD162 /* SDL_diskaudio.c in Sources */,
|
||||||
|
56A2373929F9C113003CCA5F /* SDL_sysrwlock.c in Sources */,
|
||||||
A7D8AFC523E2514200DCD162 /* SDL_egl.c in Sources */,
|
A7D8AFC523E2514200DCD162 /* SDL_egl.c in Sources */,
|
||||||
A7D8AC3823E2514100DCD162 /* SDL_RLEaccel.c in Sources */,
|
A7D8AC3823E2514100DCD162 /* SDL_RLEaccel.c in Sources */,
|
||||||
A7D8BBB623E2514500DCD162 /* SDL_assert.c in Sources */,
|
A7D8BBB623E2514500DCD162 /* SDL_assert.c in Sources */,
|
||||||
|
|
|
@ -860,6 +860,7 @@ macro(CheckPTHREAD)
|
||||||
${SDL3_SOURCE_DIR}/src/thread/pthread/SDL_systhread.c
|
${SDL3_SOURCE_DIR}/src/thread/pthread/SDL_systhread.c
|
||||||
${SDL3_SOURCE_DIR}/src/thread/pthread/SDL_sysmutex.c # Can be faked, if necessary
|
${SDL3_SOURCE_DIR}/src/thread/pthread/SDL_sysmutex.c # Can be faked, if necessary
|
||||||
${SDL3_SOURCE_DIR}/src/thread/pthread/SDL_syscond.c # Can be faked, if necessary
|
${SDL3_SOURCE_DIR}/src/thread/pthread/SDL_syscond.c # Can be faked, if necessary
|
||||||
|
${SDL3_SOURCE_DIR}/src/thread/pthread/SDL_sysrwlock.c # Can be faked, if necessary
|
||||||
${SDL3_SOURCE_DIR}/src/thread/pthread/SDL_systls.c
|
${SDL3_SOURCE_DIR}/src/thread/pthread/SDL_systls.c
|
||||||
)
|
)
|
||||||
if(HAVE_PTHREADS_SEM)
|
if(HAVE_PTHREADS_SEM)
|
||||||
|
|
|
@ -203,11 +203,9 @@ extern DECLSPEC int SDLCALL SDL_TryLockMutex(SDL_mutex * mutex) SDL_TRY_ACQUIRE(
|
||||||
* unlock it the same number of times before it is actually made available for
|
* unlock it the same number of times before it is actually made available for
|
||||||
* other threads in the system (this is known as a "recursive mutex").
|
* other threads in the system (this is known as a "recursive mutex").
|
||||||
*
|
*
|
||||||
* It is an error to unlock a mutex that has not been locked by the current
|
* It is illegal to unlock a mutex that has not been locked by the current
|
||||||
* thread, and doing so results in undefined behavior.
|
* thread, and doing so results in undefined behavior.
|
||||||
*
|
*
|
||||||
* It is also an error to unlock a mutex that isn't locked at all.
|
|
||||||
*
|
|
||||||
* \param mutex the mutex to unlock.
|
* \param mutex the mutex to unlock.
|
||||||
* \returns 0 on success or a negative error code on failure; call
|
* \returns 0 on success or a negative error code on failure; call
|
||||||
* SDL_GetError() for more information.
|
* SDL_GetError() for more information.
|
||||||
|
@ -240,6 +238,228 @@ extern DECLSPEC void SDLCALL SDL_DestroyMutex(SDL_mutex * mutex);
|
||||||
/* @} *//* Mutex functions */
|
/* @} *//* Mutex functions */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \name Read/write lock functions
|
||||||
|
*/
|
||||||
|
/* @{ */
|
||||||
|
|
||||||
|
/* The SDL read/write lock structure, defined in SDL_sysrwlock.c */
|
||||||
|
struct SDL_rwlock;
|
||||||
|
typedef struct SDL_rwlock SDL_rwlock;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Synchronization functions which can time out return this value
|
||||||
|
* if they time out.
|
||||||
|
*/
|
||||||
|
#define SDL_RWLOCK_TIMEDOUT SDL_MUTEX_TIMEDOUT
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new read/write lock.
|
||||||
|
*
|
||||||
|
* A read/write lock is useful for situations where you have multiple
|
||||||
|
* threads trying to access a resource that is rarely updated. All threads
|
||||||
|
* requesting a read-only lock will be allowed to run in parallel; if a
|
||||||
|
* thread requests a write lock, it will be provided exclusive access.
|
||||||
|
* This makes it safe for multiple threads to use a resource at the same
|
||||||
|
* time if they promise not to change it, and when it has to be changed,
|
||||||
|
* the rwlock will serve as a gateway to make sure those changes can be
|
||||||
|
* made safely.
|
||||||
|
*
|
||||||
|
* In the right situation, a rwlock can be more efficient than a mutex,
|
||||||
|
* which only lets a single thread proceed at a time, even if it won't be
|
||||||
|
* modifying the data.
|
||||||
|
*
|
||||||
|
* All newly-created read/write locks begin in the _unlocked_ state.
|
||||||
|
*
|
||||||
|
* Calls to SDL_LockRWLockForReading() and SDL_LockRWLockForWriting will
|
||||||
|
* not return while the rwlock is locked _for writing_ by another thread.
|
||||||
|
* See SDL_TryLockRWLockForReading() and SDL_TryLockRWLockForWriting() to
|
||||||
|
* attempt to lock without blocking.
|
||||||
|
*
|
||||||
|
* SDL read/write locks are only recursive for read-only locks! They
|
||||||
|
* are not guaranteed to be fair, or provide access in a FIFO manner! They
|
||||||
|
* are not guaranteed to favor writers. You may not lock a rwlock for
|
||||||
|
* both read-only and write access at the same time from the same thread
|
||||||
|
* (so you can't promote your read-only lock to a write lock without
|
||||||
|
* unlocking first).
|
||||||
|
*
|
||||||
|
* \returns the initialized and unlocked read/write lock or NULL on
|
||||||
|
* failure; call SDL_GetError() for more information.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.0.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_DestroyRWLock
|
||||||
|
* \sa SDL_LockRWLockForReading
|
||||||
|
* \sa SDL_TryLockRWLockForReading
|
||||||
|
* \sa SDL_LockRWLockForWriting
|
||||||
|
* \sa SDL_TryLockRWLockForWriting
|
||||||
|
* \sa SDL_UnlockRWLock
|
||||||
|
*/
|
||||||
|
extern DECLSPEC SDL_rwlock *SDLCALL SDL_CreateRWLock(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lock the read/write lock for _read only_ operations.
|
||||||
|
*
|
||||||
|
* This will block until the rwlock is available, which is to say it is
|
||||||
|
* not locked for writing by any other thread. Of all threads waiting to
|
||||||
|
* lock the rwlock, all may do so at the same time as long as they are
|
||||||
|
* requesting read-only access; if a thread wants to lock for writing,
|
||||||
|
* only one may do so at a time, and no other threads, read-only or not,
|
||||||
|
* may hold the lock at the same time.
|
||||||
|
*
|
||||||
|
* It is legal for the owning thread to lock an already-locked rwlock
|
||||||
|
* for reading. It must unlock it the same number of times before it is
|
||||||
|
* actually made available for other threads in the system (this is known
|
||||||
|
* as a "recursive rwlock").
|
||||||
|
*
|
||||||
|
* Note that locking for writing is not recursive (this is only available
|
||||||
|
* to read-only locks).
|
||||||
|
*
|
||||||
|
* It is illegal to request a read-only lock from a thread that already
|
||||||
|
* holds the write lock. Doing so results in undefined behavior. Unlock the
|
||||||
|
* write lock before requesting a read-only lock. (But, of course, if you
|
||||||
|
* have the write lock, you don't need further locks to read in any case.)
|
||||||
|
*
|
||||||
|
* \param rwlock the read/write lock to lock
|
||||||
|
* \returns 0 on success or a negative error code on failure; call
|
||||||
|
* SDL_GetError() for more information.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.0.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_UnlockRWLock
|
||||||
|
*/
|
||||||
|
extern DECLSPEC int SDLCALL SDL_LockRWLockForReading(SDL_rwlock * rwlock) SDL_ACQUIRE_SHARED(rwlock);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lock the read/write lock for _write_ operations.
|
||||||
|
*
|
||||||
|
* This will block until the rwlock is available, which is to say it is
|
||||||
|
* not locked for reading or writing by any other thread. Only one thread
|
||||||
|
* may hold the lock when it requests write access; all other threads,
|
||||||
|
* whether they also want to write or only want read-only access, must wait
|
||||||
|
* until the writer thread has released the lock.
|
||||||
|
*
|
||||||
|
* It is illegal for the owning thread to lock an already-locked rwlock
|
||||||
|
* for writing (read-only may be locked recursively, writing can not). Doing
|
||||||
|
* so results in undefined behavior.
|
||||||
|
*
|
||||||
|
* It is illegal to request a write lock from a thread that already holds
|
||||||
|
* a read-only lock. Doing so results in undefined behavior. Unlock the
|
||||||
|
* read-only lock before requesting a write lock.
|
||||||
|
*
|
||||||
|
* \param rwlock the read/write lock to lock
|
||||||
|
* \returns 0 on success or a negative error code on failure; call
|
||||||
|
* SDL_GetError() for more information.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.0.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_UnlockRWLock
|
||||||
|
*/
|
||||||
|
extern DECLSPEC int SDLCALL SDL_LockRWLockForWriting(SDL_rwlock * rwlock) SDL_ACQUIRE(rwlock);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to lock a read/write lock _for reading_ without blocking.
|
||||||
|
*
|
||||||
|
* This works just like SDL_LockRWLockForReading(), but if the rwlock is not
|
||||||
|
* available, then this function returns `SDL_RWLOCK_TIMEDOUT` immediately.
|
||||||
|
*
|
||||||
|
* This technique is useful if you need access to a resource but
|
||||||
|
* don't want to wait for it, and will return to it to try again later.
|
||||||
|
*
|
||||||
|
* Trying to lock for read-only access can succeed if other threads are
|
||||||
|
* holding read-only locks, as this won't prevent access.
|
||||||
|
*
|
||||||
|
* \param rwlock the rwlock to try to lock
|
||||||
|
* \returns 0, `SDL_RWLOCK_TIMEDOUT`, or -1 on error; call SDL_GetError() for
|
||||||
|
* more information.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.0.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_CreateRWLock
|
||||||
|
* \sa SDL_DestroyRWLock
|
||||||
|
* \sa SDL_TryLockRWLockForReading
|
||||||
|
* \sa SDL_UnlockRWLock
|
||||||
|
*/
|
||||||
|
extern DECLSPEC int SDLCALL SDL_TryLockRWLockForReading(SDL_rwlock * rwlock) SDL_TRY_ACQUIRE_SHARED(0, rwlock);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to lock a read/write lock _for writing_ without blocking.
|
||||||
|
*
|
||||||
|
* This works just like SDL_LockRWLockForWriting(), but if the rwlock is not available,
|
||||||
|
* this function returns `SDL_RWLOCK_TIMEDOUT` immediately.
|
||||||
|
*
|
||||||
|
* This technique is useful if you need exclusive access to a resource but
|
||||||
|
* don't want to wait for it, and will return to it to try again later.
|
||||||
|
*
|
||||||
|
* It is illegal for the owning thread to lock an already-locked rwlock
|
||||||
|
* for writing (read-only may be locked recursively, writing can not). Doing
|
||||||
|
* so results in undefined behavior.
|
||||||
|
*
|
||||||
|
* It is illegal to request a write lock from a thread that already holds
|
||||||
|
* a read-only lock. Doing so results in undefined behavior. Unlock the
|
||||||
|
* read-only lock before requesting a write lock.
|
||||||
|
*
|
||||||
|
* \param rwlock the rwlock to try to lock
|
||||||
|
* \returns 0, `SDL_RWLOCK_TIMEDOUT`, or -1 on error; call SDL_GetError() for
|
||||||
|
* more information.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.0.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_CreateRWLock
|
||||||
|
* \sa SDL_DestroyRWLock
|
||||||
|
* \sa SDL_TryLockRWLockForWriting
|
||||||
|
* \sa SDL_UnlockRWLock
|
||||||
|
*/
|
||||||
|
extern DECLSPEC int SDLCALL SDL_TryLockRWLockForWriting(SDL_rwlock * rwlock) SDL_TRY_ACQUIRE(0, rwlock);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unlock the read/write lock.
|
||||||
|
*
|
||||||
|
* Use this function to unlock the rwlock, whether it was locked for read-only
|
||||||
|
* or write operations.
|
||||||
|
*
|
||||||
|
* It is legal for the owning thread to lock an already-locked read-only lock.
|
||||||
|
* It must unlock it the same number of times before it is actually made
|
||||||
|
* available for other threads in the system (this is known as a "recursive
|
||||||
|
* rwlock").
|
||||||
|
*
|
||||||
|
* It is illegal to unlock a rwlock that has not been locked by the current
|
||||||
|
* thread, and doing so results in undefined behavior.
|
||||||
|
*
|
||||||
|
* \param rwlock the rwlock to unlock.
|
||||||
|
* \returns 0 on success or a negative error code on failure; call
|
||||||
|
* SDL_GetError() for more information.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.0.0.
|
||||||
|
*/
|
||||||
|
extern DECLSPEC int SDLCALL SDL_UnlockRWLock(SDL_rwlock * rwlock) SDL_RELEASE_SHARED(rwlock);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy a read/write lock created with SDL_CreateRWLock().
|
||||||
|
*
|
||||||
|
* This function must be called on any read/write lock that is no longer needed.
|
||||||
|
* Failure to destroy a rwlock will result in a system memory or resource leak. While
|
||||||
|
* it is safe to destroy a rwlock that is _unlocked_, it is not safe to attempt
|
||||||
|
* to destroy a locked rwlock, and may result in undefined behavior depending
|
||||||
|
* on the platform.
|
||||||
|
*
|
||||||
|
* \param rwlock the rwlock to destroy
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.0.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_CreateRWLock
|
||||||
|
* \sa SDL_LockRWLockForReading
|
||||||
|
* \sa SDL_LockRWLockForWriting
|
||||||
|
* \sa SDL_TryLockRWLockForReading
|
||||||
|
* \sa SDL_TryLockRWLockForWriting
|
||||||
|
* \sa SDL_UnlockRWLock
|
||||||
|
*/
|
||||||
|
extern DECLSPEC void SDLCALL SDL_DestroyRWLock(SDL_rwlock * rwlock);
|
||||||
|
|
||||||
|
/* @} *//* Read/write lock functions */
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \name Semaphore functions
|
* \name Semaphore functions
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -348,6 +348,7 @@
|
||||||
|
|
||||||
/* Enable various threading systems */
|
/* Enable various threading systems */
|
||||||
#cmakedefine SDL_THREAD_GENERIC_COND_SUFFIX @SDL_THREAD_GENERIC_COND_SUFFIX@
|
#cmakedefine SDL_THREAD_GENERIC_COND_SUFFIX @SDL_THREAD_GENERIC_COND_SUFFIX@
|
||||||
|
#cmakedefine SDL_THREAD_GENERIC_RWLOCK_SUFFIX @SDL_THREAD_GENERIC_RWLOCK_SUFFIX@
|
||||||
#cmakedefine SDL_THREAD_PTHREAD @SDL_THREAD_PTHREAD@
|
#cmakedefine SDL_THREAD_PTHREAD @SDL_THREAD_PTHREAD@
|
||||||
#cmakedefine SDL_THREAD_PTHREAD_RECURSIVE_MUTEX @SDL_THREAD_PTHREAD_RECURSIVE_MUTEX@
|
#cmakedefine SDL_THREAD_PTHREAD_RECURSIVE_MUTEX @SDL_THREAD_PTHREAD_RECURSIVE_MUTEX@
|
||||||
#cmakedefine SDL_THREAD_PTHREAD_RECURSIVE_MUTEX_NP @SDL_THREAD_PTHREAD_RECURSIVE_MUTEX_NP@
|
#cmakedefine SDL_THREAD_PTHREAD_RECURSIVE_MUTEX_NP @SDL_THREAD_PTHREAD_RECURSIVE_MUTEX_NP@
|
||||||
|
|
|
@ -256,6 +256,7 @@ typedef unsigned int uintptr_t;
|
||||||
|
|
||||||
/* Enable various threading systems */
|
/* Enable various threading systems */
|
||||||
#define SDL_THREAD_GENERIC_COND_SUFFIX 1
|
#define SDL_THREAD_GENERIC_COND_SUFFIX 1
|
||||||
|
#define SDL_THREAD_GENERIC_RWLOCK_SUFFIX 1
|
||||||
#define SDL_THREAD_WINDOWS 1
|
#define SDL_THREAD_WINDOWS 1
|
||||||
|
|
||||||
/* Enable various timer systems */
|
/* Enable various timer systems */
|
||||||
|
|
|
@ -196,6 +196,7 @@
|
||||||
|
|
||||||
/* Enable various threading systems */
|
/* Enable various threading systems */
|
||||||
#define SDL_THREAD_GENERIC_COND_SUFFIX 1
|
#define SDL_THREAD_GENERIC_COND_SUFFIX 1
|
||||||
|
#define SDL_THREAD_GENERIC_RWLOCK_SUFFIX 1
|
||||||
#define SDL_THREAD_WINDOWS 1
|
#define SDL_THREAD_WINDOWS 1
|
||||||
|
|
||||||
/* Enable various timer systems */
|
/* Enable various timer systems */
|
||||||
|
|
|
@ -184,6 +184,7 @@
|
||||||
/* Enable various threading systems */
|
/* Enable various threading systems */
|
||||||
#if (NTDDI_VERSION >= NTDDI_WINBLUE)
|
#if (NTDDI_VERSION >= NTDDI_WINBLUE)
|
||||||
#define SDL_THREAD_GENERIC_COND_SUFFIX 1
|
#define SDL_THREAD_GENERIC_COND_SUFFIX 1
|
||||||
|
#define SDL_THREAD_GENERIC_RWLOCK_SUFFIX 1
|
||||||
#define SDL_THREAD_WINDOWS 1
|
#define SDL_THREAD_WINDOWS 1
|
||||||
#else
|
#else
|
||||||
/* WinRT on Windows 8.0 and Windows Phone 8.0 don't support CreateThread() */
|
/* WinRT on Windows 8.0 and Windows Phone 8.0 don't support CreateThread() */
|
||||||
|
|
|
@ -196,6 +196,7 @@
|
||||||
|
|
||||||
/* Enable various threading systems */
|
/* Enable various threading systems */
|
||||||
#define SDL_THREAD_GENERIC_COND_SUFFIX 1
|
#define SDL_THREAD_GENERIC_COND_SUFFIX 1
|
||||||
|
#define SDL_THREAD_GENERIC_RWLOCK_SUFFIX 1
|
||||||
#define SDL_THREAD_WINDOWS 1
|
#define SDL_THREAD_WINDOWS 1
|
||||||
|
|
||||||
/* Enable various timer systems */
|
/* Enable various timer systems */
|
||||||
|
|
|
@ -844,6 +844,13 @@ SDL3_0.0.0 {
|
||||||
SDL_CreateWindowWithPosition;
|
SDL_CreateWindowWithPosition;
|
||||||
SDL_GetAudioStreamFormat;
|
SDL_GetAudioStreamFormat;
|
||||||
SDL_SetAudioStreamFormat;
|
SDL_SetAudioStreamFormat;
|
||||||
|
SDL_CreateRWLock;
|
||||||
|
SDL_LockRWLockForReading;
|
||||||
|
SDL_LockRWLockForWriting;
|
||||||
|
SDL_TryLockRWLockForReading;
|
||||||
|
SDL_TryLockRWLockForWriting;
|
||||||
|
SDL_UnlockRWLock;
|
||||||
|
SDL_DestroyRWLock;
|
||||||
# extra symbols go here (don't modify this line)
|
# extra symbols go here (don't modify this line)
|
||||||
local: *;
|
local: *;
|
||||||
};
|
};
|
||||||
|
|
|
@ -870,3 +870,10 @@
|
||||||
#define SDL_CreateWindowWithPosition SDL_CreateWindowWithPosition_REAL
|
#define SDL_CreateWindowWithPosition SDL_CreateWindowWithPosition_REAL
|
||||||
#define SDL_GetAudioStreamFormat SDL_GetAudioStreamFormat_REAL
|
#define SDL_GetAudioStreamFormat SDL_GetAudioStreamFormat_REAL
|
||||||
#define SDL_SetAudioStreamFormat SDL_SetAudioStreamFormat_REAL
|
#define SDL_SetAudioStreamFormat SDL_SetAudioStreamFormat_REAL
|
||||||
|
#define SDL_CreateRWLock SDL_CreateRWLock_REAL
|
||||||
|
#define SDL_LockRWLockForReading SDL_LockRWLockForReading_REAL
|
||||||
|
#define SDL_LockRWLockForWriting SDL_LockRWLockForWriting_REAL
|
||||||
|
#define SDL_TryLockRWLockForReading SDL_TryLockRWLockForReading_REAL
|
||||||
|
#define SDL_TryLockRWLockForWriting SDL_TryLockRWLockForWriting_REAL
|
||||||
|
#define SDL_UnlockRWLock SDL_UnlockRWLock_REAL
|
||||||
|
#define SDL_DestroyRWLock SDL_DestroyRWLock_REAL
|
||||||
|
|
|
@ -915,3 +915,10 @@ SDL_DYNAPI_PROC(SDL_Window*,SDL_GetWindowParent,(SDL_Window *a),(a),return)
|
||||||
SDL_DYNAPI_PROC(SDL_Window*,SDL_CreateWindowWithPosition,(const char *a, int b, int c, int d, int e, Uint32 f),(a,b,c,d,e,f),return)
|
SDL_DYNAPI_PROC(SDL_Window*,SDL_CreateWindowWithPosition,(const char *a, int b, int c, int d, int e, Uint32 f),(a,b,c,d,e,f),return)
|
||||||
SDL_DYNAPI_PROC(int,SDL_GetAudioStreamFormat,(SDL_AudioStream *a, SDL_AudioFormat *b, int *c, int *d, SDL_AudioFormat *e, int *f, int *g),(a,b,c,d,e,f,g),return)
|
SDL_DYNAPI_PROC(int,SDL_GetAudioStreamFormat,(SDL_AudioStream *a, SDL_AudioFormat *b, int *c, int *d, SDL_AudioFormat *e, int *f, int *g),(a,b,c,d,e,f,g),return)
|
||||||
SDL_DYNAPI_PROC(int,SDL_SetAudioStreamFormat,(SDL_AudioStream *a, SDL_AudioFormat b, int c, int d, SDL_AudioFormat e, int f, int g),(a,b,c,d,e,f,g),return)
|
SDL_DYNAPI_PROC(int,SDL_SetAudioStreamFormat,(SDL_AudioStream *a, SDL_AudioFormat b, int c, int d, SDL_AudioFormat e, int f, int g),(a,b,c,d,e,f,g),return)
|
||||||
|
SDL_DYNAPI_PROC(SDL_rwlock*,SDL_CreateRWLock,(void),(),return)
|
||||||
|
SDL_DYNAPI_PROC(int,SDL_LockRWLockForReading,(SDL_rwlock *a),(a),return)
|
||||||
|
SDL_DYNAPI_PROC(int,SDL_LockRWLockForWriting,(SDL_rwlock *a),(a),return)
|
||||||
|
SDL_DYNAPI_PROC(int,SDL_TryLockRWLockForReading,(SDL_rwlock *a),(a),return)
|
||||||
|
SDL_DYNAPI_PROC(int,SDL_TryLockRWLockForWriting,(SDL_rwlock *a),(a),return)
|
||||||
|
SDL_DYNAPI_PROC(int,SDL_UnlockRWLock,(SDL_rwlock *a),(a),return)
|
||||||
|
SDL_DYNAPI_PROC(void,SDL_DestroyRWLock,(SDL_rwlock *a),(a),)
|
||||||
|
|
|
@ -159,3 +159,4 @@ int SDL_UnlockMutex(SDL_mutex *mutex) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doe
|
||||||
return 0;
|
return 0;
|
||||||
#endif /* SDL_THREADS_DISABLED */
|
#endif /* SDL_THREADS_DISABLED */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,185 @@
|
||||||
|
/*
|
||||||
|
Simple DirectMedia Layer
|
||||||
|
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
#include "SDL_internal.h"
|
||||||
|
|
||||||
|
/* An implementation of rwlocks using mutexes, condition variables, and atomics. */
|
||||||
|
|
||||||
|
#include "SDL_systhread_c.h"
|
||||||
|
|
||||||
|
#include "../generic/SDL_sysrwlock_c.h"
|
||||||
|
|
||||||
|
/* If two implementations are to be compiled into SDL (the active one
|
||||||
|
* will be chosen at runtime), the function names need to be
|
||||||
|
* suffixed
|
||||||
|
*/
|
||||||
|
/* !!! FIXME: this is quite a tapdance with macros and the build system, maybe we can simplify how we do this. --ryan. */
|
||||||
|
#ifndef SDL_THREAD_GENERIC_RWLOCK_SUFFIX
|
||||||
|
#define SDL_CreateRWLock_generic SDL_CreateRWLock
|
||||||
|
#define SDL_DestroyRWLock_generic SDL_DestroyRWLock
|
||||||
|
#define SDL_LockRWLockForReading_generic SDL_LockRWLockForReading
|
||||||
|
#define SDL_LockRWLockForWriting_generic SDL_LockRWLockForWriting
|
||||||
|
#define SDL_TryLockRWLockForReading_generic SDL_TryLockRWLockForReading
|
||||||
|
#define SDL_TryLockRWLockForWriting_generic SDL_TryLockRWLockForWriting
|
||||||
|
#define SDL_UnlockRWLock_generic SDL_UnlockRWLock
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct SDL_rwlock
|
||||||
|
{
|
||||||
|
SDL_mutex *lock;
|
||||||
|
SDL_cond *condition;
|
||||||
|
SDL_threadID writer_thread;
|
||||||
|
SDL_AtomicInt reader_count;
|
||||||
|
SDL_AtomicInt writer_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
SDL_rwlock *SDL_CreateRWLock_generic(void)
|
||||||
|
{
|
||||||
|
SDL_rwlock *rwlock = (SDL_rwlock *) SDL_malloc(sizeof (*rwlock));
|
||||||
|
|
||||||
|
if (!rwlock) {
|
||||||
|
SDL_OutOfMemory();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rwlock->lock = SDL_CreateMutex();
|
||||||
|
if (!rwlock->lock) {
|
||||||
|
SDL_free(rwlock);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rwlock->condition = SDL_CreateCond();
|
||||||
|
if (!rwlock->condition) {
|
||||||
|
SDL_DestroyMutex(rwlock->lock);
|
||||||
|
SDL_free(rwlock);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_AtomicSet(&rwlock->reader_count, 0);
|
||||||
|
SDL_AtomicSet(&rwlock->writer_count, 0);
|
||||||
|
|
||||||
|
return rwlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDL_DestroyRWLock_generic(SDL_rwlock *rwlock)
|
||||||
|
{
|
||||||
|
if (rwlock) {
|
||||||
|
SDL_DestroyMutex(rwlock->lock);
|
||||||
|
SDL_DestroyCond(rwlock->condition);
|
||||||
|
SDL_free(rwlock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int SDL_LockRWLockForReading_generic(SDL_rwlock *rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
|
||||||
|
{
|
||||||
|
if (!rwlock) {
|
||||||
|
return SDL_InvalidParamError("rwlock");
|
||||||
|
} else if (SDL_LockMutex(rwlock->lock) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_assert(SDL_AtomicGet(&rwlock->writer_count) == 0); /* shouldn't be able to grab lock if there's a writer! */
|
||||||
|
|
||||||
|
SDL_AtomicAdd(&rwlock->reader_count, 1);
|
||||||
|
SDL_UnlockMutex(rwlock->lock); /* other readers can attempt to share the lock. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SDL_LockRWLockForWriting_generic(SDL_rwlock *rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
|
||||||
|
{
|
||||||
|
if (!rwlock) {
|
||||||
|
return SDL_InvalidParamError("rwlock");
|
||||||
|
} else if (SDL_LockMutex(rwlock->lock) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (SDL_AtomicGet(&rwlock->reader_count) > 0) { /* while something is holding the shared lock, keep waiting. */
|
||||||
|
SDL_CondWait(rwlock->condition, rwlock->lock); /* release the lock and wait for readers holding the shared lock to release it, regrab the lock. */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we hold the lock! */
|
||||||
|
SDL_AtomicAdd(&rwlock->writer_count, 1); /* we let these be recursive, but the API doesn't require this. It _does_ trust you unlock correctly! */
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SDL_TryLockRWLockForReading_generic(SDL_rwlock *rwlock)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (!rwlock) {
|
||||||
|
return SDL_InvalidParamError("rwlock");
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = SDL_TryLockMutex(rwlock->lock);
|
||||||
|
if (rc != 0) {
|
||||||
|
/* !!! FIXME: there is a small window where a reader has to lock the mutex, and if we hit that, we will return SDL_RWLOCK_TIMEDOUT even though we could have shared the lock. */
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_assert(SDL_AtomicGet(&rwlock->writer_count) == 0); /* shouldn't be able to grab lock if there's a writer! */
|
||||||
|
|
||||||
|
SDL_AtomicAdd(&rwlock->reader_count, 1);
|
||||||
|
SDL_UnlockMutex(rwlock->lock); /* other readers can attempt to share the lock. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SDL_TryLockRWLockForWriting_generic(SDL_rwlock *rwlock)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (!rwlock) {
|
||||||
|
return SDL_InvalidParamError("rwlock");
|
||||||
|
} else if ((rc = SDL_TryLockMutex(rwlock->lock)) != 0) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SDL_AtomicGet(&rwlock->reader_count) > 0) { /* a reader is using the shared lock, treat it as unavailable. */
|
||||||
|
SDL_UnlockMutex(rwlock->lock);
|
||||||
|
return SDL_RWLOCK_TIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we hold the lock! */
|
||||||
|
SDL_AtomicAdd(&rwlock->writer_count, 1); /* we let these be recursive, but the API doesn't require this. It _does_ trust you unlock correctly! */
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SDL_UnlockRWLock_generic(SDL_rwlock *rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
|
||||||
|
{
|
||||||
|
if (!rwlock) {
|
||||||
|
return SDL_InvalidParamError("rwlock");
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_LockMutex(rwlock->lock); /* recursive lock for writers, readers grab lock to make sure things are sane. */
|
||||||
|
|
||||||
|
if (SDL_AtomicGet(&rwlock->reader_count) > 0) { /* we're a reader */
|
||||||
|
SDL_AtomicAdd(&rwlock->reader_count, -1);
|
||||||
|
SDL_CondBroadcast(rwlock->condition); /* alert any pending writers to attempt to try to grab the lock again. */
|
||||||
|
} else if (SDL_AtomicGet(&rwlock->writer_count) > 0) { /* we're a writer */
|
||||||
|
SDL_AtomicAdd(&rwlock->writer_count, -1);
|
||||||
|
SDL_UnlockMutex(rwlock->lock); /* recursive unlock. */
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_UnlockMutex(rwlock->lock);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
Simple DirectMedia Layer
|
||||||
|
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
#include "SDL_internal.h"
|
||||||
|
|
||||||
|
#ifndef SDL_sysrwlock_c_h_
|
||||||
|
#define SDL_sysrwlock_c_h_
|
||||||
|
|
||||||
|
#ifdef SDL_THREAD_GENERIC_RWLOCK_SUFFIX
|
||||||
|
|
||||||
|
SDL_rwlock *SDL_CreateRWLock_generic(void);
|
||||||
|
void SDL_DestroyRWLock_generic(SDL_rwlock *rwlock);
|
||||||
|
int SDL_LockRWLockForReading_generic(SDL_rwlock *rwlock);
|
||||||
|
int SDL_LockRWLockForWriting_generic(SDL_rwlock *rwlock);
|
||||||
|
int SDL_TryLockRWLockForReading_generic(SDL_rwlock *rwlock);
|
||||||
|
int SDL_TryLockRWLockForWriting_generic(SDL_rwlock *rwlock);
|
||||||
|
int SDL_UnlockRWLock_generic(SDL_rwlock *rwlock);
|
||||||
|
|
||||||
|
#endif /* SDL_THREAD_GENERIC_RWLOCK_SUFFIX */
|
||||||
|
|
||||||
|
#endif /* SDL_sysrwlock_c_h_ */
|
|
@ -109,3 +109,4 @@ int SDL_UnlockMutex(SDL_mutex *mutex) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doe
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
|
|
||||||
#include <e32std.h>
|
#include <e32std.h>
|
||||||
|
|
||||||
|
/* !!! FIXME: Should this be SDL_MUTEX_TIMEDOUT? */
|
||||||
#define SDL_MUTEX_TIMEOUT -2
|
#define SDL_MUTEX_TIMEOUT -2
|
||||||
|
|
||||||
struct SDL_semaphore
|
struct SDL_semaphore
|
||||||
|
|
|
@ -23,20 +23,7 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#include "SDL_sysmutex_c.h"
|
||||||
#if !(defined(SDL_THREAD_PTHREAD_RECURSIVE_MUTEX) || \
|
|
||||||
defined(SDL_THREAD_PTHREAD_RECURSIVE_MUTEX_NP))
|
|
||||||
#define FAKE_RECURSIVE_MUTEX
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct SDL_mutex
|
|
||||||
{
|
|
||||||
pthread_mutex_t id;
|
|
||||||
#ifdef FAKE_RECURSIVE_MUTEX
|
|
||||||
int recursive;
|
|
||||||
pthread_t owner;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
SDL_mutex *
|
SDL_mutex *
|
||||||
SDL_CreateMutex(void)
|
SDL_CreateMutex(void)
|
||||||
|
@ -186,3 +173,4 @@ int SDL_UnlockMutex(SDL_mutex *mutex) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doe
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,9 +23,18 @@
|
||||||
#ifndef SDL_mutex_c_h_
|
#ifndef SDL_mutex_c_h_
|
||||||
#define SDL_mutex_c_h_
|
#define SDL_mutex_c_h_
|
||||||
|
|
||||||
|
#if !(defined(SDL_THREAD_PTHREAD_RECURSIVE_MUTEX) || \
|
||||||
|
defined(SDL_THREAD_PTHREAD_RECURSIVE_MUTEX_NP))
|
||||||
|
#define FAKE_RECURSIVE_MUTEX
|
||||||
|
#endif
|
||||||
|
|
||||||
struct SDL_mutex
|
struct SDL_mutex
|
||||||
{
|
{
|
||||||
pthread_mutex_t id;
|
pthread_mutex_t id;
|
||||||
|
#ifdef FAKE_RECURSIVE_MUTEX
|
||||||
|
int recursive;
|
||||||
|
pthread_t owner;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* SDL_mutex_c_h_ */
|
#endif /* SDL_mutex_c_h_ */
|
||||||
|
|
|
@ -0,0 +1,127 @@
|
||||||
|
/*
|
||||||
|
Simple DirectMedia Layer
|
||||||
|
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
#include "SDL_internal.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
struct SDL_rwlock
|
||||||
|
{
|
||||||
|
pthread_rwlock_t id;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
SDL_rwlock *
|
||||||
|
SDL_CreateRWLock(void)
|
||||||
|
{
|
||||||
|
SDL_rwlock *rwlock;
|
||||||
|
|
||||||
|
/* Allocate the structure */
|
||||||
|
rwlock = (SDL_rwlock *)SDL_calloc(1, sizeof(*rwlock));
|
||||||
|
if (rwlock) {
|
||||||
|
if (pthread_rwlock_init(&rwlock->id, NULL) != 0) {
|
||||||
|
SDL_SetError("pthread_rwlock_init() failed");
|
||||||
|
SDL_free(rwlock);
|
||||||
|
rwlock = NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
SDL_OutOfMemory();
|
||||||
|
}
|
||||||
|
return rwlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDL_DestroyRWLock(SDL_rwlock *rwlock)
|
||||||
|
{
|
||||||
|
if (rwlock) {
|
||||||
|
pthread_rwlock_destroy(&rwlock->id);
|
||||||
|
SDL_free(rwlock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int SDL_LockRWLockForReading(SDL_rwlock *rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
|
||||||
|
{
|
||||||
|
if (rwlock == NULL) {
|
||||||
|
return SDL_InvalidParamError("rwlock");
|
||||||
|
} else if (pthread_rwlock_rdlock(&rwlock->id) != 0) {
|
||||||
|
return SDL_SetError("pthread_rwlock_rdlock() failed");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SDL_LockRWLockForWriting(SDL_rwlock *rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
|
||||||
|
{
|
||||||
|
if (rwlock == NULL) {
|
||||||
|
return SDL_InvalidParamError("rwlock");
|
||||||
|
} else if (pthread_rwlock_wrlock(&rwlock->id) != 0) {
|
||||||
|
return SDL_SetError("pthread_rwlock_wrlock() failed");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SDL_TryLockRWLockForReading(SDL_rwlock *rwlock)
|
||||||
|
{
|
||||||
|
int retval = 0;
|
||||||
|
|
||||||
|
if (rwlock == NULL) {
|
||||||
|
retval = SDL_InvalidParamError("rwlock");
|
||||||
|
} else {
|
||||||
|
const int result = pthread_rwlock_tryrdlock(&rwlock->id);
|
||||||
|
if (result != 0) {
|
||||||
|
if (result == EBUSY) {
|
||||||
|
retval = SDL_RWLOCK_TIMEDOUT;
|
||||||
|
} else {
|
||||||
|
retval = SDL_SetError("pthread_rwlock_tryrdlock() failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SDL_TryLockRWLockForWriting(SDL_rwlock *rwlock)
|
||||||
|
{
|
||||||
|
int retval = 0;
|
||||||
|
|
||||||
|
if (rwlock == NULL) {
|
||||||
|
retval = SDL_InvalidParamError("rwlock");
|
||||||
|
} else {
|
||||||
|
const int result = pthread_rwlock_trywrlock(&rwlock->id);
|
||||||
|
if (result != 0) {
|
||||||
|
if (result == EBUSY) {
|
||||||
|
retval = SDL_RWLOCK_TIMEDOUT;
|
||||||
|
} else {
|
||||||
|
retval = SDL_SetError("pthread_rwlock_tryrdlock() failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SDL_UnlockRWLock(SDL_rwlock *rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
|
||||||
|
{
|
||||||
|
if (rwlock == NULL) {
|
||||||
|
return SDL_InvalidParamError("rwlock");
|
||||||
|
} else if (pthread_rwlock_unlock(&rwlock->id) != 0) {
|
||||||
|
return SDL_SetError("pthread_rwlock_unlock() failed");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -97,3 +97,4 @@ SDL_UnlockMutex(SDL_mutex *mutex) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't
|
||||||
mutex->cpp_mutex.unlock();
|
mutex->cpp_mutex.unlock();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,3 +26,4 @@ struct SDL_mutex
|
||||||
{
|
{
|
||||||
std::recursive_mutex cpp_mutex;
|
std::recursive_mutex cpp_mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,130 @@
|
||||||
|
/*
|
||||||
|
Simple DirectMedia Layer
|
||||||
|
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
#include "SDL_internal.h"
|
||||||
|
|
||||||
|
#include <shared_mutex>
|
||||||
|
#include <system_error>
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
|
struct SDL_rwlock
|
||||||
|
{
|
||||||
|
std::shared_mutex cpp_mutex;
|
||||||
|
SDL_threadID write_owner;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Create a rwlock */
|
||||||
|
extern "C" SDL_rwlock *SDL_CreateRWLock(void)
|
||||||
|
{
|
||||||
|
/* Allocate and initialize the rwlock */
|
||||||
|
try {
|
||||||
|
SDL_rwlock *rwlock = new SDL_rwlock;
|
||||||
|
return rwlock;
|
||||||
|
} catch (std::system_error &ex) {
|
||||||
|
SDL_SetError("unable to create a C++ rwlock: code=%d; %s", ex.code(), ex.what());
|
||||||
|
return NULL;
|
||||||
|
} catch (std::bad_alloc &) {
|
||||||
|
SDL_OutOfMemory();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free the rwlock */
|
||||||
|
extern "C" void SDL_DestroyRWLock(SDL_rwlock *rwlock)
|
||||||
|
{
|
||||||
|
if (rwlock != NULL) {
|
||||||
|
delete rwlock;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Lock the rwlock */
|
||||||
|
extern "C" int SDL_LockRWLockForReading(SDL_rwlock *rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
|
||||||
|
{
|
||||||
|
if (!rwlock) {
|
||||||
|
return SDL_InvalidParamError("rwlock");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
rwlock->cpp_mutex.lock_shared();
|
||||||
|
return 0;
|
||||||
|
} catch (std::system_error &ex) {
|
||||||
|
return SDL_SetError("unable to lock a C++ rwlock: code=%d; %s", ex.code(), ex.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Lock the rwlock for writing */
|
||||||
|
extern "C" int SDL_LockRWLockForWriting(SDL_rwlock *rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
|
||||||
|
{
|
||||||
|
if (!rwlock) {
|
||||||
|
return SDL_InvalidParamError("rwlock");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
rwlock->cpp_mutex.lock();
|
||||||
|
rwlock->write_owner = SDL_ThreadID();
|
||||||
|
return 0;
|
||||||
|
} catch (std::system_error &ex) {
|
||||||
|
return SDL_SetError("unable to lock a C++ rwlock: code=%d; %s", ex.code(), ex.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TryLock the rwlock for reading */
|
||||||
|
int SDL_TryLockRWLockForReading(SDL_rwlock *rwlock)
|
||||||
|
{
|
||||||
|
int retval = 0;
|
||||||
|
|
||||||
|
if (!rwlock) {
|
||||||
|
retval = SDL_InvalidParamError("rwlock");
|
||||||
|
} else if (rwlock->cpp_mutex.try_lock_shared() == false) {
|
||||||
|
retval = SDL_RWLOCK_TIMEDOUT;
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TryLock the rwlock for writing */
|
||||||
|
int SDL_TryLockRWLockForWriting(SDL_rwlock *rwlock)
|
||||||
|
{
|
||||||
|
int retval = 0;
|
||||||
|
|
||||||
|
if (!rwlock) {
|
||||||
|
retval = SDL_InvalidParamError("rwlock");
|
||||||
|
} else if (rwlock->cpp_mutex.try_lock() == false) {
|
||||||
|
retval = SDL_RWLOCK_TIMEDOUT;
|
||||||
|
} else {
|
||||||
|
rwlock->write_owner = SDL_ThreadID();
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unlock the rwlock */
|
||||||
|
extern "C" int
|
||||||
|
SDL_UnlockRWLock(SDL_rwlock *rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
|
||||||
|
{
|
||||||
|
if (!rwlock) {
|
||||||
|
return SDL_InvalidParamError("rwlock");
|
||||||
|
} else if (rwlock->write_owner == SDL_ThreadID()) {
|
||||||
|
rwlock->write_owner = 0;
|
||||||
|
rwlock->cpp_mutex.unlock();
|
||||||
|
} else {
|
||||||
|
rwlock->cpp_mutex.unlock_shared();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,258 @@
|
||||||
|
/*
|
||||||
|
Simple DirectMedia Layer
|
||||||
|
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
#include "SDL_internal.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation based on Slim Reader/Writer (SRW) Locks for Win 7 and newer.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* This header makes sure SRWLOCK is actually declared, even on ancient WinSDKs. */
|
||||||
|
#include "SDL_sysmutex_c.h"
|
||||||
|
|
||||||
|
typedef VOID(WINAPI *pfnInitializeSRWLock)(PSRWLOCK);
|
||||||
|
typedef VOID(WINAPI *pfnReleaseSRWLockShared)(PSRWLOCK);
|
||||||
|
typedef VOID(WINAPI *pfnAcquireSRWLockShared)(PSRWLOCK);
|
||||||
|
typedef BOOLEAN(WINAPI *pfnTryAcquireSRWLockShared)(PSRWLOCK);
|
||||||
|
typedef VOID(WINAPI *pfnReleaseSRWLockExclusive)(PSRWLOCK);
|
||||||
|
typedef VOID(WINAPI *pfnAcquireSRWLockExclusive)(PSRWLOCK);
|
||||||
|
typedef BOOLEAN(WINAPI *pfnTryAcquireSRWLockExclusive)(PSRWLOCK);
|
||||||
|
|
||||||
|
#ifdef __WINRT__
|
||||||
|
/* Functions are guaranteed to be available */
|
||||||
|
#define pTryAcquireSRWLockExclusive TryAcquireSRWLockExclusive
|
||||||
|
#define pInitializeSRWLock InitializeSRWLock
|
||||||
|
#define pReleaseSRWLockShared ReleaseSRWLockShared
|
||||||
|
#define pAcquireSRWLockShared AcquireSRWLockShared
|
||||||
|
#define pTryAcquireSRWLockShared TryAcquireSRWLockShared
|
||||||
|
#define pReleaseSRWLockExclusive ReleaseSRWLockExclusive
|
||||||
|
#define pAcquireSRWLockExclusive AcquireSRWLockExclusive
|
||||||
|
#define pTryAcquireSRWLockExclusive TryAcquireSRWLockExclusive
|
||||||
|
#else
|
||||||
|
static pfnInitializeSRWLock pInitializeSRWLock = NULL;
|
||||||
|
static pfnReleaseSRWLockShared pReleaseSRWLockShared = NULL;
|
||||||
|
static pfnAcquireSRWLockShared pAcquireSRWLockShared = NULL;
|
||||||
|
static pfnTryAcquireSRWLockShared pTryAcquireSRWLockShared = NULL;
|
||||||
|
static pfnReleaseSRWLockExclusive pReleaseSRWLockExclusive = NULL;
|
||||||
|
static pfnAcquireSRWLockExclusive pAcquireSRWLockExclusive = NULL;
|
||||||
|
static pfnTryAcquireSRWLockExclusive pTryAcquireSRWLockExclusive = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef SDL_rwlock *(*pfnSDL_CreateRWLock)(void);
|
||||||
|
typedef void (*pfnSDL_DestroyRWLock)(SDL_rwlock *);
|
||||||
|
typedef int (*pfnSDL_LockRWLockForReading)(SDL_rwlock *);
|
||||||
|
typedef int (*pfnSDL_LockRWLockForWriting)(SDL_rwlock *);
|
||||||
|
typedef int (*pfnSDL_TryLockRWLockForReading)(SDL_rwlock *);
|
||||||
|
typedef int (*pfnSDL_TryLockRWLockForWriting)(SDL_rwlock *);
|
||||||
|
typedef int (*pfnSDL_UnlockRWLock)(SDL_rwlock *);
|
||||||
|
|
||||||
|
typedef struct SDL_rwlock_impl_t
|
||||||
|
{
|
||||||
|
pfnSDL_CreateRWLock Create;
|
||||||
|
pfnSDL_DestroyRWLock Destroy;
|
||||||
|
pfnSDL_LockRWLockForReading LockForReading;
|
||||||
|
pfnSDL_LockRWLockForWriting LockForWriting;
|
||||||
|
pfnSDL_TryLockRWLockForReading TryLockForReading;
|
||||||
|
pfnSDL_TryLockRWLockForWriting TryLockForWriting;
|
||||||
|
pfnSDL_UnlockRWLock Unlock;
|
||||||
|
} SDL_rwlock_impl_t;
|
||||||
|
|
||||||
|
/* Implementation will be chosen at runtime based on available Kernel features */
|
||||||
|
static SDL_rwlock_impl_t SDL_rwlock_impl_active = { 0 };
|
||||||
|
|
||||||
|
/* rwlock implementation using Win7+ slim read/write locks (SRWLOCK) */
|
||||||
|
|
||||||
|
typedef struct SDL_rwlock_srw
|
||||||
|
{
|
||||||
|
SRWLOCK srw;
|
||||||
|
SDL_threadID write_owner;
|
||||||
|
} SDL_rwlock_srw;
|
||||||
|
|
||||||
|
static SDL_rwlock *SDL_CreateRWLock_srw(void)
|
||||||
|
{
|
||||||
|
SDL_rwlock_srw *rwlock = (SDL_rwlock_srw *)SDL_calloc(1, sizeof(*rwlock));
|
||||||
|
if (rwlock == NULL) {
|
||||||
|
SDL_OutOfMemory();
|
||||||
|
}
|
||||||
|
pInitializeSRWLock(&rwlock->srw);
|
||||||
|
return (SDL_rwlock *)rwlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SDL_DestroyRWLock_srw(SDL_rwlock *_rwlock)
|
||||||
|
{
|
||||||
|
SDL_rwlock_srw *rwlock = (SDL_rwlock_srw *) _rwlock;
|
||||||
|
if (rwlock) {
|
||||||
|
/* There are no kernel allocated resources */
|
||||||
|
SDL_free(rwlock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int SDL_LockRWLockForReading_srw(SDL_rwlock *_rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
|
||||||
|
{
|
||||||
|
SDL_rwlock_srw *rwlock = (SDL_rwlock_srw *) _rwlock;
|
||||||
|
if (rwlock == NULL) {
|
||||||
|
return SDL_InvalidParamError("rwlock");
|
||||||
|
}
|
||||||
|
pAcquireSRWLockShared(&rwlock->srw);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int SDL_LockRWLockForWriting_srw(SDL_rwlock *_rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
|
||||||
|
{
|
||||||
|
SDL_rwlock_srw *rwlock = (SDL_rwlock_srw *) _rwlock;
|
||||||
|
if (rwlock == NULL) {
|
||||||
|
return SDL_InvalidParamError("rwlock");
|
||||||
|
}
|
||||||
|
pAcquireSRWLockExclusive(&rwlock->srw);
|
||||||
|
rwlock->write_owner = SDL_ThreadID();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int SDL_TryLockRWLockForReading_srw(SDL_rwlock *_rwlock)
|
||||||
|
{
|
||||||
|
SDL_rwlock_srw *rwlock = (SDL_rwlock_srw *) _rwlock;
|
||||||
|
int retval = 0;
|
||||||
|
|
||||||
|
if (rwlock == NULL) {
|
||||||
|
retval = SDL_InvalidParamError("rwlock");
|
||||||
|
} else {
|
||||||
|
retval = pTryAcquireSRWLockShared(&rwlock->srw) ? 0 : SDL_RWLOCK_TIMEDOUT;
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int SDL_TryLockRWLockForWriting_srw(SDL_rwlock *_rwlock)
|
||||||
|
{
|
||||||
|
SDL_rwlock_srw *rwlock = (SDL_rwlock_srw *) _rwlock;
|
||||||
|
int retval = 0;
|
||||||
|
|
||||||
|
if (rwlock == NULL) {
|
||||||
|
retval = SDL_InvalidParamError("rwlock");
|
||||||
|
} else {
|
||||||
|
retval = pTryAcquireSRWLockExclusive(&rwlock->srw) ? 0 : SDL_RWLOCK_TIMEDOUT;
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int SDL_UnlockRWLock_srw(SDL_rwlock *_rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
|
||||||
|
{
|
||||||
|
SDL_rwlock_srw *rwlock = (SDL_rwlock_srw *) _rwlock;
|
||||||
|
if (rwlock == NULL) {
|
||||||
|
return SDL_InvalidParamError("rwlock");
|
||||||
|
} else if (rwlock->write_owner == SDL_ThreadID()) {
|
||||||
|
rwlock->write_owner = 0;
|
||||||
|
pReleaseSRWLockExclusive(&rwlock->srw);
|
||||||
|
} else {
|
||||||
|
pReleaseSRWLockShared(&rwlock->srw);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const SDL_rwlock_impl_t SDL_rwlock_impl_srw = {
|
||||||
|
&SDL_CreateRWLock_srw,
|
||||||
|
&SDL_DestroyRWLock_srw,
|
||||||
|
&SDL_LockRWLockForReading_srw,
|
||||||
|
&SDL_LockRWLockForWriting_srw,
|
||||||
|
&SDL_TryLockRWLockForReading_srw,
|
||||||
|
&SDL_TryLockRWLockForWriting_srw,
|
||||||
|
&SDL_UnlockRWLock_srw
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifndef __WINRT__
|
||||||
|
|
||||||
|
#include "../generic/SDL_sysrwlock_c.h"
|
||||||
|
|
||||||
|
/* Generic rwlock implementation using SDL_mutex, SDL_cond, and SDL_AtomicInt */
|
||||||
|
static const SDL_rwlock_impl_t SDL_rwlock_impl_generic = {
|
||||||
|
&SDL_CreateRWLock_generic,
|
||||||
|
&SDL_DestroyRWLock_generic,
|
||||||
|
&SDL_LockRWLockForReading_generic,
|
||||||
|
&SDL_LockRWLockForWriting_generic,
|
||||||
|
&SDL_TryLockRWLockForReading_generic,
|
||||||
|
&SDL_TryLockRWLockForWriting_generic,
|
||||||
|
&SDL_UnlockRWLock_generic
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SDL_rwlock *SDL_CreateRWLock(void)
|
||||||
|
{
|
||||||
|
if (SDL_rwlock_impl_active.Create == NULL) {
|
||||||
|
const SDL_rwlock_impl_t *impl;
|
||||||
|
|
||||||
|
#ifdef __WINRT__
|
||||||
|
/* Link statically on this platform */
|
||||||
|
impl = &SDL_rwlock_impl_srw;
|
||||||
|
#else
|
||||||
|
/* Default to generic implementation, works with all mutex implementations */
|
||||||
|
impl = &SDL_rwlock_impl_generic;
|
||||||
|
{
|
||||||
|
HMODULE kernel32 = GetModuleHandle(TEXT("kernel32.dll"));
|
||||||
|
if (kernel32) {
|
||||||
|
SDL_bool okay = SDL_TRUE;
|
||||||
|
#define LOOKUP_SRW_SYM(sym) if (okay) { if ((p##sym = (pfn##sym)GetProcAddress(kernel32, #sym)) == NULL) { okay = SDL_FALSE; } }
|
||||||
|
LOOKUP_SRW_SYM(InitializeSRWLock);
|
||||||
|
LOOKUP_SRW_SYM(ReleaseSRWLockShared);
|
||||||
|
LOOKUP_SRW_SYM(AcquireSRWLockShared);
|
||||||
|
LOOKUP_SRW_SYM(TryAcquireSRWLockShared);
|
||||||
|
LOOKUP_SRW_SYM(ReleaseSRWLockExclusive);
|
||||||
|
LOOKUP_SRW_SYM(AcquireSRWLockExclusive);
|
||||||
|
LOOKUP_SRW_SYM(TryAcquireSRWLockExclusive);
|
||||||
|
#undef LOOKUP_SRW_SYM
|
||||||
|
if (okay) {
|
||||||
|
impl = &SDL_rwlock_impl_srw; /* Use the Windows provided API instead of generic fallback */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SDL_copyp(&SDL_rwlock_impl_active, impl);
|
||||||
|
}
|
||||||
|
return SDL_rwlock_impl_active.Create();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDL_DestroyRWLock(SDL_rwlock *rwlock)
|
||||||
|
{
|
||||||
|
SDL_rwlock_impl_active.Destroy(rwlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
int SDL_LockRWLockForReading(SDL_rwlock *rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
|
||||||
|
{
|
||||||
|
return SDL_rwlock_impl_active.LockForReading(rwlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
int SDL_LockRWLockForWriting(SDL_rwlock *rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
|
||||||
|
{
|
||||||
|
return SDL_rwlock_impl_active.LockForWriting(rwlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
int SDL_TryLockRWLockForReading(SDL_rwlock *rwlock)
|
||||||
|
{
|
||||||
|
return SDL_rwlock_impl_active.TryLockForReading(rwlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
int SDL_TryLockRWLockForWriting(SDL_rwlock *rwlock)
|
||||||
|
{
|
||||||
|
return SDL_rwlock_impl_active.TryLockForWriting(rwlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
int SDL_UnlockRWLock(SDL_rwlock *rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
|
||||||
|
{
|
||||||
|
return SDL_rwlock_impl_active.Unlock(rwlock);
|
||||||
|
}
|
|
@ -225,6 +225,7 @@ add_sdl_test_executable(testkeys SOURCES testkeys.c)
|
||||||
add_sdl_test_executable(testloadso SOURCES testloadso.c)
|
add_sdl_test_executable(testloadso SOURCES testloadso.c)
|
||||||
add_sdl_test_executable(testlocale NONINTERACTIVE SOURCES testlocale.c)
|
add_sdl_test_executable(testlocale NONINTERACTIVE SOURCES testlocale.c)
|
||||||
add_sdl_test_executable(testlock SOURCES testlock.c)
|
add_sdl_test_executable(testlock SOURCES testlock.c)
|
||||||
|
add_sdl_test_executable(testrwlock SOURCES testrwlock.c)
|
||||||
add_sdl_test_executable(testmouse SOURCES testmouse.c)
|
add_sdl_test_executable(testmouse SOURCES testmouse.c)
|
||||||
|
|
||||||
add_sdl_test_executable(testoverlay NEEDS_RESOURCES TESTUTILS SOURCES testoverlay.c)
|
add_sdl_test_executable(testoverlay NEEDS_RESOURCES TESTUTILS SOURCES testoverlay.c)
|
||||||
|
|
|
@ -0,0 +1,179 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Test the thread and rwlock locking functions
|
||||||
|
Also exercises the system's signal/thread interaction
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
#include <SDL3/SDL_main.h>
|
||||||
|
#include <SDL3/SDL_test.h>
|
||||||
|
|
||||||
|
static SDL_rwlock *rwlock = NULL;
|
||||||
|
static SDL_threadID mainthread;
|
||||||
|
static SDL_AtomicInt doterminate;
|
||||||
|
static int nb_threads = 6;
|
||||||
|
static SDL_Thread **threads;
|
||||||
|
static int worktime = 1000;
|
||||||
|
static int writerworktime = 100;
|
||||||
|
static int timeout = 10000;
|
||||||
|
static SDLTest_CommonState *state;
|
||||||
|
|
||||||
|
static void DoWork(const int workticks) /* "Work" */
|
||||||
|
{
|
||||||
|
const SDL_threadID tid = SDL_ThreadID();
|
||||||
|
const SDL_bool is_reader = tid != mainthread;
|
||||||
|
const char *typestr = is_reader ? "Reader" : "Writer";
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
SDL_Log("%s Thread %lu: ready to work\n", typestr, (unsigned long) tid);
|
||||||
|
rc = is_reader ? SDL_LockRWLockForReading(rwlock) : SDL_LockRWLockForWriting(rwlock);
|
||||||
|
if (rc < 0) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "%s Thread %lu: Couldn't lock rwlock: %s", typestr, (unsigned long) tid, SDL_GetError());
|
||||||
|
} else {
|
||||||
|
SDL_Log("%s Thread %lu: start work!\n", typestr, (unsigned long) tid);
|
||||||
|
SDL_Delay(workticks);
|
||||||
|
SDL_Log("%s Thread %lu: work done!\n", typestr, (unsigned long) tid);
|
||||||
|
if (SDL_UnlockRWLock(rwlock) < 0) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "%s Thread %lu: Couldn't unlock rwlock: %s", typestr, (unsigned long) tid, SDL_GetError());
|
||||||
|
}
|
||||||
|
/* If this sleep isn't done, then threads may starve */
|
||||||
|
SDL_Delay(10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int SDLCALL
|
||||||
|
ReaderRun(void *data)
|
||||||
|
{
|
||||||
|
SDL_Log("Reader Thread %lu: starting up", SDL_ThreadID());
|
||||||
|
while (!SDL_AtomicGet(&doterminate)) {
|
||||||
|
DoWork(worktime);
|
||||||
|
}
|
||||||
|
SDL_Log("Reader Thread %lu: exiting!\n", SDL_ThreadID());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Initialize test framework */
|
||||||
|
state = SDLTest_CommonCreateState(argv, 0);
|
||||||
|
if (state == NULL) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_AtomicSet(&doterminate, 0);
|
||||||
|
|
||||||
|
/* Enable standard application logging */
|
||||||
|
SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
|
||||||
|
/* Parse commandline */
|
||||||
|
for (i = 1; i < argc;) {
|
||||||
|
int consumed;
|
||||||
|
|
||||||
|
consumed = SDLTest_CommonArg(state, i);
|
||||||
|
if (!consumed) {
|
||||||
|
if (SDL_strcmp(argv[i], "--nbthreads") == 0) {
|
||||||
|
if (argv[i + 1]) {
|
||||||
|
char *endptr;
|
||||||
|
nb_threads = SDL_strtol(argv[i + 1], &endptr, 0);
|
||||||
|
if (endptr != argv[i + 1] && *endptr == '\0' && nb_threads > 0) {
|
||||||
|
consumed = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (SDL_strcmp(argv[i], "--worktime") == 0) {
|
||||||
|
if (argv[i + 1]) {
|
||||||
|
char *endptr;
|
||||||
|
worktime = SDL_strtol(argv[i + 1], &endptr, 0);
|
||||||
|
if (endptr != argv[i + 1] && *endptr == '\0' && worktime > 0) {
|
||||||
|
consumed = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (SDL_strcmp(argv[i], "--writerworktime") == 0) {
|
||||||
|
if (argv[i + 1]) {
|
||||||
|
char *endptr;
|
||||||
|
writerworktime = SDL_strtol(argv[i + 1], &endptr, 0);
|
||||||
|
if (endptr != argv[i + 1] && *endptr == '\0' && writerworktime > 0) {
|
||||||
|
consumed = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (SDL_strcmp(argv[i], "--timeout") == 0) {
|
||||||
|
if (argv[i + 1]) {
|
||||||
|
char *endptr;
|
||||||
|
timeout = (Uint64) SDL_strtol(argv[i + 1], &endptr, 0);
|
||||||
|
if (endptr != argv[i + 1] && *endptr == '\0' && timeout > 0) {
|
||||||
|
consumed = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (consumed <= 0) {
|
||||||
|
static const char *options[] = {
|
||||||
|
"[--nbthreads NB]",
|
||||||
|
"[--worktime ms]",
|
||||||
|
"[--writerworktime ms]",
|
||||||
|
"[--timeout ms]",
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
SDLTest_CommonLogUsage(state, argv[0], options);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
i += consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
threads = SDL_malloc(nb_threads * sizeof(SDL_Thread*));
|
||||||
|
|
||||||
|
/* Load the SDL library */
|
||||||
|
if (SDL_Init(0) < 0) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "%s\n", SDL_GetError());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_AtomicSet(&doterminate, 0);
|
||||||
|
|
||||||
|
rwlock = SDL_CreateRWLock();
|
||||||
|
if (rwlock == NULL) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create rwlock: %s\n", SDL_GetError());
|
||||||
|
SDL_Quit();
|
||||||
|
SDLTest_CommonDestroyState(state);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
mainthread = SDL_ThreadID();
|
||||||
|
SDL_Log("Writer thread: %lu\n", mainthread);
|
||||||
|
for (i = 0; i < nb_threads; ++i) {
|
||||||
|
char name[64];
|
||||||
|
(void)SDL_snprintf(name, sizeof(name), "Reader%d", i);
|
||||||
|
threads[i] = SDL_CreateThread(ReaderRun, name, NULL);
|
||||||
|
if (threads[i] == NULL) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create reader thread! %s\n", SDL_GetError());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!SDL_AtomicGet(&doterminate) && (SDL_GetTicks() < ((Uint64) timeout))) {
|
||||||
|
DoWork(writerworktime);
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_AtomicSet(&doterminate, 1);
|
||||||
|
SDL_Log("Waiting on reader threads to terminate...");
|
||||||
|
for (i = 0; i < nb_threads; ++i) {
|
||||||
|
SDL_WaitThread(threads[i], NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Log("Reader threads have terminated, quitting!");
|
||||||
|
SDL_DestroyRWLock(rwlock);
|
||||||
|
SDLTest_CommonDestroyState(state);
|
||||||
|
SDL_Quit();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue