From b5e3de76cb27f052b47920ca987e6976fbe3a6b2 Mon Sep 17 00:00:00 2001 From: narzoul Date: Mon, 1 Jun 2020 17:12:34 +0200 Subject: [PATCH] Use QueryThreadCycleTime for mitigation of busy waiting --- DDrawCompat/Common/Time.h | 7 +++ DDrawCompat/Config/Config.h | 11 ++-- DDrawCompat/DDrawCompat.vcxproj | 2 - DDrawCompat/DDrawCompat.vcxproj.filters | 6 --- DDrawCompat/Dll/DllMain.cpp | 2 - DDrawCompat/Win32/TimeFunctions.cpp | 37 -------------- DDrawCompat/Win32/TimeFunctions.h | 9 ---- DDrawCompat/Win32/WaitFunctions.cpp | 68 ++++++++++--------------- 8 files changed, 39 insertions(+), 103 deletions(-) delete mode 100644 DDrawCompat/Win32/TimeFunctions.cpp delete mode 100644 DDrawCompat/Win32/TimeFunctions.h diff --git a/DDrawCompat/Common/Time.h b/DDrawCompat/Common/Time.h index 56098ed..93e11c9 100644 --- a/DDrawCompat/Common/Time.h +++ b/DDrawCompat/Common/Time.h @@ -24,4 +24,11 @@ namespace Time QueryPerformanceCounter(&qpc); return qpc.QuadPart; } + + inline ULONG64 queryThreadCycleTime() + { + ULONG64 cycleTime = 0; + QueryThreadCycleTime(GetCurrentThread(), &cycleTime); + return cycleTime; + } } diff --git a/DDrawCompat/Config/Config.h b/DDrawCompat/Config/Config.h index 2720b36..01d3cb2 100644 --- a/DDrawCompat/Config/Config.h +++ b/DDrawCompat/Config/Config.h @@ -1,11 +1,10 @@ #pragma once -typedef unsigned long DWORD; - namespace Config { - const int delayedFlipModeTimeout = 200; - const int evictionTimeout = 200; - const int maxPaletteUpdatesPerMs = 5; - const int maxUserModeDisplayDrivers = 3; + const unsigned delayedFlipModeTimeout = 200; + const unsigned evictionTimeout = 200; + const unsigned maxPaletteUpdatesPerMs = 5; + const unsigned maxUserModeDisplayDrivers = 3; + const unsigned threadSwitchCycleTime = 3 * 1000 * 1000; } diff --git a/DDrawCompat/DDrawCompat.vcxproj b/DDrawCompat/DDrawCompat.vcxproj index f166d58..1aeae37 100644 --- a/DDrawCompat/DDrawCompat.vcxproj +++ b/DDrawCompat/DDrawCompat.vcxproj @@ -231,7 +231,6 @@ - @@ -302,7 +301,6 @@ - diff --git a/DDrawCompat/DDrawCompat.vcxproj.filters b/DDrawCompat/DDrawCompat.vcxproj.filters index 45ef71b..d6e6de0 100644 --- a/DDrawCompat/DDrawCompat.vcxproj.filters +++ b/DDrawCompat/DDrawCompat.vcxproj.filters @@ -357,9 +357,6 @@ Header Files\Win32 - - Header Files\Win32 - Header Files\Direct3d @@ -572,9 +569,6 @@ Source Files\Win32 - - Source Files\Win32 - Source Files\Direct3d diff --git a/DDrawCompat/Dll/DllMain.cpp b/DDrawCompat/Dll/DllMain.cpp index e41add3..5edc9ef 100644 --- a/DDrawCompat/Dll/DllMain.cpp +++ b/DDrawCompat/Dll/DllMain.cpp @@ -20,7 +20,6 @@ #include #include #include -#include #include HRESULT WINAPI SetAppCompatData(DWORD, DWORD); @@ -106,7 +105,6 @@ namespace Compat::Log() << "Installing Direct3D driver hooks"; D3dDdi::installHooks(g_origDDrawModule); Compat::Log() << "Installing Win32 hooks"; - Win32::TimeFunctions::installHooks(); Win32::WaitFunctions::installHooks(); Gdi::VirtualScreen::init(); diff --git a/DDrawCompat/Win32/TimeFunctions.cpp b/DDrawCompat/Win32/TimeFunctions.cpp deleted file mode 100644 index d7b23ca..0000000 --- a/DDrawCompat/Win32/TimeFunctions.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include -#include - -#include -#include - -namespace -{ - typedef DWORD(WINAPI* TimeFunc)(); - - template - DWORD WINAPI getTime() - { - thread_local DWORD prevTime = 0; - auto origTimeFunc = Compat::getOrigFuncPtr(); - DWORD time = origTimeFunc(); - if (prevTime == time) - { - SwitchToThread(); - time = origTimeFunc(); - } - prevTime = time; - return time; - } -} - -namespace Win32 -{ - namespace TimeFunctions - { - void installHooks() - { - HOOK_FUNCTION(kernel32, GetTickCount, getTime<&GetTickCount>); - HOOK_FUNCTION(winmm, timeGetTime, getTime<&timeGetTime>); - } - } -} diff --git a/DDrawCompat/Win32/TimeFunctions.h b/DDrawCompat/Win32/TimeFunctions.h deleted file mode 100644 index 4a2e836..0000000 --- a/DDrawCompat/Win32/TimeFunctions.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -namespace Win32 -{ - namespace TimeFunctions - { - void installHooks(); - } -} diff --git a/DDrawCompat/Win32/WaitFunctions.cpp b/DDrawCompat/Win32/WaitFunctions.cpp index d31b74f..431a35a 100644 --- a/DDrawCompat/Win32/WaitFunctions.cpp +++ b/DDrawCompat/Win32/WaitFunctions.cpp @@ -1,66 +1,52 @@ #include +#include -#include #include +#include +#include #include namespace { - DWORD mitigateBusyWaiting(DWORD dwMilliseconds, DWORD waitResult) + void mitigateBusyWaiting() { - if (0 == dwMilliseconds && WAIT_TIMEOUT == waitResult) + thread_local ULONG64 ctLastThreadSwitch = Time::queryThreadCycleTime(); + ULONG64 ctNow = Time::queryThreadCycleTime(); + if (ctNow - ctLastThreadSwitch >= Config::threadSwitchCycleTime) { - SwitchToThread(); + Sleep(0); + ctLastThreadSwitch = ctNow; } - return waitResult; } - DWORD WINAPI msgWaitForMultipleObjects( - DWORD nCount, const HANDLE* pHandles, BOOL fWaitAll, DWORD dwMilliseconds, DWORD dwWakeMask) + template + Result WINAPI mitigatedBusyWaitingFunc(Params... params) { - return mitigateBusyWaiting(dwMilliseconds, CALL_ORIG_FUNC(MsgWaitForMultipleObjects)( - nCount, pHandles, fWaitAll, dwMilliseconds, dwWakeMask)); - } - - DWORD WINAPI msgWaitForMultipleObjectsEx( - DWORD nCount, const HANDLE* pHandles, DWORD dwMilliseconds, DWORD dwWakeMask, DWORD dwFlags) - { - return mitigateBusyWaiting(dwMilliseconds, CALL_ORIG_FUNC(MsgWaitForMultipleObjectsEx)( - nCount, pHandles, dwMilliseconds, dwWakeMask, dwFlags)); - } - - DWORD WINAPI signalObjectAndWait( - HANDLE hObjectToSignal, HANDLE hObjectToWaitOn, DWORD dwMilliseconds, BOOL bAlertable) - { - return mitigateBusyWaiting(dwMilliseconds, CALL_ORIG_FUNC(SignalObjectAndWait)( - hObjectToSignal, hObjectToWaitOn, dwMilliseconds, bAlertable)); - } - - DWORD WINAPI waitForSingleObjectEx(HANDLE hHandle, DWORD dwMilliseconds, BOOL bAlertable) - { - return mitigateBusyWaiting(dwMilliseconds, CALL_ORIG_FUNC(WaitForSingleObjectEx)( - hHandle, dwMilliseconds, bAlertable)); - } - - DWORD WINAPI waitForMultipleObjectsEx( - DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAll, DWORD dwMilliseconds, BOOL bAlertable) - { - return mitigateBusyWaiting(dwMilliseconds, CALL_ORIG_FUNC(WaitForMultipleObjectsEx)( - nCount, lpHandles, bWaitAll, dwMilliseconds, bAlertable)); + mitigateBusyWaiting(); + return Compat::getOrigFuncPtr()(params...); } } +#define MITIGATE_BUSY_WAITING(module, func) \ + Compat::hookFunction(#module, #func, &mitigatedBusyWaitingFunc) + namespace Win32 { namespace WaitFunctions { void installHooks() { - HOOK_FUNCTION(user32, MsgWaitForMultipleObjects, msgWaitForMultipleObjects); - HOOK_FUNCTION(user32, MsgWaitForMultipleObjectsEx, msgWaitForMultipleObjectsEx); - HOOK_FUNCTION(kernel32, SignalObjectAndWait, signalObjectAndWait); - HOOK_FUNCTION(kernel32, WaitForSingleObjectEx, waitForSingleObjectEx); - HOOK_FUNCTION(kernel32, WaitForMultipleObjectsEx, waitForMultipleObjectsEx); + MITIGATE_BUSY_WAITING(user32, GetMessageA); + MITIGATE_BUSY_WAITING(user32, GetMessageW); + MITIGATE_BUSY_WAITING(kernel32, GetTickCount); + MITIGATE_BUSY_WAITING(user32, MsgWaitForMultipleObjects); + MITIGATE_BUSY_WAITING(user32, MsgWaitForMultipleObjectsEx); + MITIGATE_BUSY_WAITING(user32, PeekMessageA); + MITIGATE_BUSY_WAITING(user32, PeekMessageW); + MITIGATE_BUSY_WAITING(kernel32, SignalObjectAndWait); + MITIGATE_BUSY_WAITING(winmm, timeGetTime); + MITIGATE_BUSY_WAITING(kernel32, WaitForSingleObjectEx); + MITIGATE_BUSY_WAITING(kernel32, WaitForMultipleObjectsEx); } } }