mirror of https://github.com/libsdl-org/SDL
rwlock: Added SDL_rwlock API for shared locks.
This commit is contained in:
parent
776820526b
commit
e474047ff8
|
@ -2008,11 +2008,14 @@ elseif(WINDOWS)
|
|||
|
||||
if(SDL_THREADS)
|
||||
set(SDL_THREAD_GENERIC_COND_SUFFIX 1)
|
||||
set(SDL_THREAD_GENERIC_RWLOCK_SUFFIX 1)
|
||||
set(SDL_THREAD_WINDOWS 1)
|
||||
list(APPEND SOURCE_FILES
|
||||
${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_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_systhread.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_systhread.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)
|
||||
set(HAVE_SDL_THREADS TRUE)
|
||||
endif()
|
||||
|
@ -2732,7 +2736,7 @@ elseif(PSP)
|
|||
endif()
|
||||
if(SDL_THREADS)
|
||||
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})
|
||||
set(HAVE_SDL_THREADS TRUE)
|
||||
endif()
|
||||
|
@ -2791,7 +2795,7 @@ elseif(PS2)
|
|||
endif()
|
||||
if(SDL_THREADS)
|
||||
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})
|
||||
set(HAVE_SDL_THREADS TRUE)
|
||||
endif()
|
||||
|
@ -2852,7 +2856,7 @@ elseif(N3DS)
|
|||
if(SDL_THREADS)
|
||||
set(SDL_THREAD_N3DS 1)
|
||||
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)
|
||||
endif()
|
||||
|
||||
|
|
|
@ -1225,6 +1225,9 @@
|
|||
<ClCompile Include="..\..\src\thread\windows\SDL_sysmutex.c">
|
||||
<Filter>thread\windows</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\thread\windows\SDL_sysrwlock_srw.c">
|
||||
<Filter>thread\windows</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\thread\windows\SDL_syssem.c">
|
||||
<Filter>thread\windows</Filter>
|
||||
</ClCompile>
|
||||
|
@ -1237,6 +1240,9 @@
|
|||
<ClCompile Include="..\..\src\thread\generic\SDL_syscond.c">
|
||||
<Filter>thread\generic</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\thread\generic\SDL_sysrwlock.c">
|
||||
<Filter>thread\generic</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\stdlib\SDL_crc16.c">
|
||||
<Filter>stdlib</Filter>
|
||||
</ClCompile>
|
||||
|
|
|
@ -444,6 +444,24 @@
|
|||
<CompileAsWinRT Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</CompileAsWinRT>
|
||||
<CompileAsWinRT Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</CompileAsWinRT>
|
||||
</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">
|
||||
<PrecompiledHeaderOutputFile Condition="'$(Configuration)|$(Platform)'=='Debug|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">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\thread\stdcpp\SDL_sysrwlock.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\thread\stdcpp\SDL_systhread.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
|
|
@ -402,6 +402,7 @@
|
|||
<ClInclude Include="..\..\src\thread\SDL_thread_c.h" />
|
||||
<ClInclude Include="..\..\src\thread\generic\SDL_syscond_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\timer\SDL_timer_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_strtokr.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\windows\SDL_syscond_cv.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_systhread.c" />
|
||||
<ClCompile Include="..\..\src\thread\windows\SDL_systls.c" />
|
||||
|
|
|
@ -1213,6 +1213,9 @@
|
|||
<ClCompile Include="..\..\src\thread\windows\SDL_sysmutex.c">
|
||||
<Filter>thread\windows</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\thread\windows\SDL_sysrwlock_srw.c">
|
||||
<Filter>thread\windows</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\thread\windows\SDL_syssem.c">
|
||||
<Filter>thread\windows</Filter>
|
||||
</ClCompile>
|
||||
|
|
|
@ -83,6 +83,15 @@
|
|||
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 */; };
|
||||
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 */; };
|
||||
56C523811D8F498C001F2F30 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00D0D08310675DD9004B05EF /* CoreFoundation.framework */; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
|
@ -4691,6 +4701,7 @@
|
|||
A7D8A78123E2513E00DCD162 /* pthread */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
56A2373229F9C113003CCA5F /* SDL_sysrwlock.c */,
|
||||
A7D8A78523E2513E00DCD162 /* SDL_syscond.c */,
|
||||
A7D8A78823E2513E00DCD162 /* SDL_sysmutex_c.h */,
|
||||
A7D8A78723E2513E00DCD162 /* SDL_sysmutex.c */,
|
||||
|
@ -7328,6 +7339,7 @@
|
|||
A75FCE7023E25AB700529352 /* SDL_hidapi_xboxone.c in Sources */,
|
||||
A75FCE7123E25AB700529352 /* SDL_blit_auto.c in Sources */,
|
||||
A75FCE7323E25AB700529352 /* SDL_keyboard.c in Sources */,
|
||||
56A2373A29F9C113003CCA5F /* SDL_sysrwlock.c in Sources */,
|
||||
A75FCE7523E25AB700529352 /* SDL_rect.c in Sources */,
|
||||
A75FCE7623E25AB700529352 /* SDL_cocoaopengles.m in Sources */,
|
||||
A75FCE7723E25AB700529352 /* SDL_qsort.c in Sources */,
|
||||
|
@ -7523,6 +7535,7 @@
|
|||
A75FD02923E25AC700529352 /* SDL_hidapi_xboxone.c in Sources */,
|
||||
A75FD02A23E25AC700529352 /* SDL_blit_auto.c in Sources */,
|
||||
A75FD02C23E25AC700529352 /* SDL_keyboard.c in Sources */,
|
||||
56A2373B29F9C113003CCA5F /* SDL_sysrwlock.c in Sources */,
|
||||
A75FD02E23E25AC700529352 /* SDL_rect.c in Sources */,
|
||||
A75FD02F23E25AC700529352 /* SDL_cocoaopengles.m in Sources */,
|
||||
A75FD03023E25AC700529352 /* SDL_qsort.c in Sources */,
|
||||
|
@ -7718,6 +7731,7 @@
|
|||
A769B20423E259AE00872273 /* SDL_hidapi_switch.c in Sources */,
|
||||
F3984CD525BCC92900374F43 /* SDL_hidapi_stadia.c in Sources */,
|
||||
A769B20523E259AE00872273 /* SDL_strtokr.c in Sources */,
|
||||
56A2373829F9C113003CCA5F /* SDL_sysrwlock.c in Sources */,
|
||||
5605720B2473687A00B46B66 /* SDL_syslocale.m in Sources */,
|
||||
F3820718284F3609004DD584 /* controller_type.c in Sources */,
|
||||
A769B20623E259AE00872273 /* SDL_clipboardevents.c in Sources */,
|
||||
|
@ -7913,6 +7927,7 @@
|
|||
A7D8BB6A23E2514500DCD162 /* SDL_keyboard.c in Sources */,
|
||||
A7D8ACE823E2514100DCD162 /* SDL_rect.c in Sources */,
|
||||
A7D8AE9B23E2514100DCD162 /* SDL_cocoaopengles.m in Sources */,
|
||||
56A2373429F9C113003CCA5F /* SDL_sysrwlock.c in Sources */,
|
||||
A7D8B96923E2514400DCD162 /* SDL_qsort.c in Sources */,
|
||||
A7D8B55223E2514300DCD162 /* SDL_hidapi_switch.c in Sources */,
|
||||
A7D8B96323E2514400DCD162 /* SDL_strtokr.c in Sources */,
|
||||
|
@ -8108,6 +8123,7 @@
|
|||
A7D8BB6B23E2514500DCD162 /* SDL_keyboard.c in Sources */,
|
||||
A7D8ACE923E2514100DCD162 /* SDL_rect.c in Sources */,
|
||||
A7D8AE9C23E2514100DCD162 /* SDL_cocoaopengles.m in Sources */,
|
||||
56A2373529F9C113003CCA5F /* SDL_sysrwlock.c in Sources */,
|
||||
A7D8B96A23E2514400DCD162 /* SDL_qsort.c in Sources */,
|
||||
A7D8B55323E2514300DCD162 /* SDL_hidapi_switch.c in Sources */,
|
||||
A7D8B96423E2514400DCD162 /* SDL_strtokr.c in Sources */,
|
||||
|
@ -8303,6 +8319,7 @@
|
|||
A7D8B55523E2514300DCD162 /* SDL_hidapi_switch.c in Sources */,
|
||||
F3984CD425BCC92900374F43 /* SDL_hidapi_stadia.c in Sources */,
|
||||
A7D8B96623E2514400DCD162 /* SDL_strtokr.c in Sources */,
|
||||
56A2373729F9C113003CCA5F /* SDL_sysrwlock.c in Sources */,
|
||||
560572092473687900B46B66 /* SDL_syslocale.m in Sources */,
|
||||
F3820717284F3609004DD584 /* controller_type.c in Sources */,
|
||||
A7D8BB7923E2514500DCD162 /* SDL_clipboardevents.c in Sources */,
|
||||
|
@ -8469,6 +8486,7 @@
|
|||
A7D8ADE623E2514100DCD162 /* SDL_blit_0.c in Sources */,
|
||||
A7D8BB0923E2514500DCD162 /* k_tan.c in Sources */,
|
||||
A7D8B8A823E2514400DCD162 /* SDL_diskaudio.c in Sources */,
|
||||
56A2373329F9C113003CCA5F /* SDL_sysrwlock.c in Sources */,
|
||||
566E26CF246274CC00718109 /* SDL_syslocale.m in Sources */,
|
||||
A7D8AFC023E2514200DCD162 /* SDL_egl.c in Sources */,
|
||||
A7D8AC3323E2514100DCD162 /* SDL_RLEaccel.c in Sources */,
|
||||
|
@ -8663,6 +8681,7 @@
|
|||
A7D8BBF223E2574800DCD162 /* SDL_uikitevents.m in Sources */,
|
||||
A7D8BBB923E2560500DCD162 /* SDL_steamcontroller.c in Sources */,
|
||||
A7D8B8AB23E2514400DCD162 /* SDL_diskaudio.c in Sources */,
|
||||
56A2373629F9C113003CCA5F /* SDL_sysrwlock.c in Sources */,
|
||||
A7D8AFC323E2514200DCD162 /* SDL_egl.c in Sources */,
|
||||
A7D8AC3623E2514100DCD162 /* SDL_RLEaccel.c in Sources */,
|
||||
A7D8BBB423E2514500DCD162 /* SDL_assert.c in Sources */,
|
||||
|
@ -8857,6 +8876,7 @@
|
|||
A7D8ADEB23E2514100DCD162 /* SDL_blit_0.c in Sources */,
|
||||
A7D8BB0E23E2514500DCD162 /* k_tan.c in Sources */,
|
||||
A7D8B8AD23E2514400DCD162 /* SDL_diskaudio.c in Sources */,
|
||||
56A2373929F9C113003CCA5F /* SDL_sysrwlock.c in Sources */,
|
||||
A7D8AFC523E2514200DCD162 /* SDL_egl.c in Sources */,
|
||||
A7D8AC3823E2514100DCD162 /* SDL_RLEaccel.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_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_sysrwlock.c # Can be faked, if necessary
|
||||
${SDL3_SOURCE_DIR}/src/thread/pthread/SDL_systls.c
|
||||
)
|
||||
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
|
||||
* 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.
|
||||
*
|
||||
* It is also an error to unlock a mutex that isn't locked at all.
|
||||
*
|
||||
* \param mutex the mutex to unlock.
|
||||
* \returns 0 on success or a negative error code on failure; call
|
||||
* SDL_GetError() for more information.
|
||||
|
@ -240,6 +238,228 @@ extern DECLSPEC void SDLCALL SDL_DestroyMutex(SDL_mutex * mutex);
|
|||
/* @} *//* 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
|
||||
*/
|
||||
|
|
|
@ -348,6 +348,7 @@
|
|||
|
||||
/* Enable various threading systems */
|
||||
#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_RECURSIVE_MUTEX @SDL_THREAD_PTHREAD_RECURSIVE_MUTEX@
|
||||
#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 */
|
||||
#define SDL_THREAD_GENERIC_COND_SUFFIX 1
|
||||
#define SDL_THREAD_GENERIC_RWLOCK_SUFFIX 1
|
||||
#define SDL_THREAD_WINDOWS 1
|
||||
|
||||
/* Enable various timer systems */
|
||||
|
|
|
@ -196,6 +196,7 @@
|
|||
|
||||
/* Enable various threading systems */
|
||||
#define SDL_THREAD_GENERIC_COND_SUFFIX 1
|
||||
#define SDL_THREAD_GENERIC_RWLOCK_SUFFIX 1
|
||||
#define SDL_THREAD_WINDOWS 1
|
||||
|
||||
/* Enable various timer systems */
|
||||
|
|
|
@ -184,6 +184,7 @@
|
|||
/* Enable various threading systems */
|
||||
#if (NTDDI_VERSION >= NTDDI_WINBLUE)
|
||||
#define SDL_THREAD_GENERIC_COND_SUFFIX 1
|
||||
#define SDL_THREAD_GENERIC_RWLOCK_SUFFIX 1
|
||||
#define SDL_THREAD_WINDOWS 1
|
||||
#else
|
||||
/* WinRT on Windows 8.0 and Windows Phone 8.0 don't support CreateThread() */
|
||||
|
|
|
@ -196,6 +196,7 @@
|
|||
|
||||
/* Enable various threading systems */
|
||||
#define SDL_THREAD_GENERIC_COND_SUFFIX 1
|
||||
#define SDL_THREAD_GENERIC_RWLOCK_SUFFIX 1
|
||||
#define SDL_THREAD_WINDOWS 1
|
||||
|
||||
/* Enable various timer systems */
|
||||
|
|
|
@ -844,6 +844,13 @@ SDL3_0.0.0 {
|
|||
SDL_CreateWindowWithPosition;
|
||||
SDL_GetAudioStreamFormat;
|
||||
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)
|
||||
local: *;
|
||||
};
|
||||
|
|
|
@ -870,3 +870,10 @@
|
|||
#define SDL_CreateWindowWithPosition SDL_CreateWindowWithPosition_REAL
|
||||
#define SDL_GetAudioStreamFormat SDL_GetAudioStreamFormat_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(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(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;
|
||||
#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;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include <e32std.h>
|
||||
|
||||
/* !!! FIXME: Should this be SDL_MUTEX_TIMEDOUT? */
|
||||
#define SDL_MUTEX_TIMEOUT -2
|
||||
|
||||
struct SDL_semaphore
|
||||
|
|
|
@ -23,20 +23,7 @@
|
|||
#include <errno.h>
|
||||
#include <pthread.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
|
||||
};
|
||||
#include "SDL_sysmutex_c.h"
|
||||
|
||||
SDL_mutex *
|
||||
SDL_CreateMutex(void)
|
||||
|
@ -186,3 +173,4 @@ int SDL_UnlockMutex(SDL_mutex *mutex) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doe
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,9 +23,18 @@
|
|||
#ifndef 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
|
||||
{
|
||||
pthread_mutex_t id;
|
||||
#ifdef FAKE_RECURSIVE_MUTEX
|
||||
int recursive;
|
||||
pthread_t owner;
|
||||
#endif
|
||||
};
|
||||
|
||||
#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();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,3 +26,4 @@ struct SDL_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(testlocale NONINTERACTIVE SOURCES testlocale.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(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