From 8e8eeb083a8e732d64e69d7277e4cacc0d0f6aae Mon Sep 17 00:00:00 2001 From: narzoul Date: Wed, 2 Jan 2019 18:52:06 +0100 Subject: [PATCH] Fixed deadlock when hooking NVIDIA user-mode display drivers See issue #28 --- DDrawCompat/Gdi/Dc.cpp | 13 ++++++----- DDrawCompat/Gdi/DcCache.cpp | 13 +++++------ DDrawCompat/Gdi/Palette.cpp | 19 ++++++++-------- DDrawCompat/Gdi/VirtualScreen.cpp | 36 +++++++++++++++---------------- DDrawCompat/Gdi/VirtualScreen.h | 4 ++-- 5 files changed, 45 insertions(+), 40 deletions(-) diff --git a/DDrawCompat/Gdi/Dc.cpp b/DDrawCompat/Gdi/Dc.cpp index b74e7b4..22b82a8 100644 --- a/DDrawCompat/Gdi/Dc.cpp +++ b/DDrawCompat/Gdi/Dc.cpp @@ -4,6 +4,7 @@ #include "Common/Hook.h" #include "Common/Log.h" +#include "Common/ScopedCriticalSection.h" #include "DDraw/ScopedThreadLock.h" #include "Gdi/Dc.h" #include "Gdi/DcCache.h" @@ -29,6 +30,7 @@ namespace typedef std::unordered_map CompatDcMap; + Compat::CriticalSection g_cs; CompatDcMap g_origDcToCompatDc; void restoreDc(const CompatDc& compatDc); @@ -147,7 +149,7 @@ namespace Gdi { void dllProcessDetach() { - DDraw::ScopedThreadLock lock; + Compat::ScopedCriticalSection lock(g_cs); for (auto& origDcToCompatDc : g_origDcToCompatDc) { restoreDc(origDcToCompatDc.second); @@ -158,7 +160,7 @@ namespace Gdi void dllThreadDetach() { - DDraw::ScopedThreadLock lock; + Compat::ScopedCriticalSection lock(g_cs); const DWORD threadId = GetCurrentThreadId(); auto it = g_origDcToCompatDc.begin(); while (it != g_origDcToCompatDc.end()) @@ -183,7 +185,8 @@ namespace Gdi return nullptr; } - DDraw::ScopedThreadLock lock; + DDraw::ScopedThreadLock ddLock; + Compat::ScopedCriticalSection lock(g_cs); auto it = g_origDcToCompatDc.find(origDc); if (it != g_origDcToCompatDc.end()) { @@ -228,7 +231,7 @@ namespace Gdi HDC getOrigDc(HDC dc) { - DDraw::ScopedThreadLock lock; + Compat::ScopedCriticalSection lock(g_cs); const auto it = std::find_if(g_origDcToCompatDc.begin(), g_origDcToCompatDc.end(), [dc](const CompatDcMap::value_type& compatDc) { return compatDc.second.dc == dc; }); return it != g_origDcToCompatDc.end() ? it->first : dc; @@ -236,7 +239,7 @@ namespace Gdi void releaseDc(HDC origDc) { - DDraw::ScopedThreadLock lock; + Compat::ScopedCriticalSection lock(g_cs); auto it = g_origDcToCompatDc.find(origDc); if (it == g_origDcToCompatDc.end()) { diff --git a/DDrawCompat/Gdi/DcCache.cpp b/DDrawCompat/Gdi/DcCache.cpp index 89571e3..a6edc3b 100644 --- a/DDrawCompat/Gdi/DcCache.cpp +++ b/DDrawCompat/Gdi/DcCache.cpp @@ -3,12 +3,13 @@ #include #include -#include "DDraw/ScopedThreadLock.h" +#include "Common/ScopedCriticalSection.h" #include "Gdi/DcCache.h" #include "Gdi/VirtualScreen.h" namespace { + Compat::CriticalSection g_cs; std::map> g_threadIdToDcCache; } @@ -18,7 +19,7 @@ namespace Gdi { void deleteDc(HDC cachedDc) { - DDraw::ScopedThreadLock lock; + Compat::ScopedCriticalSection lock(g_cs); for (auto& threadIdToDcCache : g_threadIdToDcCache) { auto& dcCache = threadIdToDcCache.second; @@ -34,7 +35,7 @@ namespace Gdi void dllProcessDetach() { - DDraw::ScopedThreadLock lock; + Compat::ScopedCriticalSection lock(g_cs); for (auto& threadIdToDcCache : g_threadIdToDcCache) { for (HDC dc : threadIdToDcCache.second) @@ -47,7 +48,7 @@ namespace Gdi void dllThreadDetach() { - DDraw::ScopedThreadLock lock; + Compat::ScopedCriticalSection lock(g_cs); auto it = g_threadIdToDcCache.find(GetCurrentThreadId()); if (it == g_threadIdToDcCache.end()) { @@ -64,7 +65,7 @@ namespace Gdi HDC getDc() { - DDraw::ScopedThreadLock lock; + Compat::ScopedCriticalSection lock(g_cs); std::vector& dcCache = g_threadIdToDcCache[GetCurrentThreadId()]; if (dcCache.empty()) @@ -79,7 +80,7 @@ namespace Gdi void releaseDc(HDC cachedDc) { - DDraw::ScopedThreadLock lock; + Compat::ScopedCriticalSection lock(g_cs); g_threadIdToDcCache[GetCurrentThreadId()].push_back(cachedDc); } } diff --git a/DDrawCompat/Gdi/Palette.cpp b/DDrawCompat/Gdi/Palette.cpp index bfb5433..ec27fb1 100644 --- a/DDrawCompat/Gdi/Palette.cpp +++ b/DDrawCompat/Gdi/Palette.cpp @@ -6,7 +6,7 @@ #include "Common/Hook.h" #include "Common/Log.h" -#include "DDraw/ScopedThreadLock.h" +#include "Common/ScopedCriticalSection.h" #include "Gdi/Gdi.h" #include "Gdi/Palette.h" #include "VirtualScreen.h" @@ -14,6 +14,7 @@ namespace { + Compat::CriticalSection g_cs; PALETTEENTRY g_systemPalette[256] = {}; UINT g_systemPaletteUse = SYSPAL_STATIC; UINT g_systemPaletteFirstUnusedIndex = 10; @@ -75,7 +76,7 @@ namespace ++g_systemPaletteFirstUnusedIndex; } - Gdi::VirtualScreen::updatePalette(); + Gdi::VirtualScreen::updatePalette(g_systemPalette); return count; } @@ -102,7 +103,7 @@ namespace nEntries = 256 - iStartIndex; } - DDraw::ScopedThreadLock lock; + Compat::ScopedCriticalSection lock(g_cs); std::memcpy(lppe, &g_systemPalette[iStartIndex], nEntries * sizeof(PALETTEENTRY)); return LOG_RESULT(nEntries); @@ -115,7 +116,7 @@ namespace { return LOG_RESULT(SYSPAL_ERROR); } - DDraw::ScopedThreadLock lock; + Compat::ScopedCriticalSection lock(g_cs); return g_systemPaletteUse; } @@ -124,7 +125,7 @@ namespace LOG_FUNC("RealizePalette", hdc); if (Gdi::isDisplayDc(hdc)) { - DDraw::ScopedThreadLock lock; + Compat::ScopedCriticalSection lock(g_cs); if (g_foregroundPaletteDcs.find(hdc) != g_foregroundPaletteDcs.end()) { g_systemPaletteFirstUnusedIndex = g_systemPaletteFirstNonReservedIndex; @@ -137,7 +138,7 @@ namespace int WINAPI releaseDc(HWND hWnd, HDC hDC) { LOG_FUNC("ReleaseDC", hWnd, hDC); - DDraw::ScopedThreadLock lock; + Compat::ScopedCriticalSection lock(g_cs); g_foregroundPaletteDcs.erase(hDC); return LOG_RESULT(CALL_ORIG_FUNC(ReleaseDC)(hWnd, hDC)); } @@ -151,7 +152,7 @@ namespace HWND wnd = CALL_ORIG_FUNC(WindowFromDC)(hdc); if (wnd && GetDesktopWindow() != wnd) { - DDraw::ScopedThreadLock lock; + Compat::ScopedCriticalSection lock(g_cs); if (bForceBackground || GetStockObject(DEFAULT_PALETTE) == hpal) { g_foregroundPaletteDcs.erase(hdc); @@ -173,7 +174,7 @@ namespace return LOG_RESULT(SYSPAL_ERROR); } - DDraw::ScopedThreadLock lock; + Compat::ScopedCriticalSection lock(g_cs); const UINT prevUsage = g_systemPaletteUse; switch (uUsage) { @@ -210,7 +211,7 @@ namespace Gdi HPALETTE defaultPalette = reinterpret_cast(GetStockObject(DEFAULT_PALETTE)); GetPaletteEntries(defaultPalette, 0, 10, g_systemPalette); GetPaletteEntries(defaultPalette, 10, 10, &g_systemPalette[246]); - Gdi::VirtualScreen::updatePalette(); + Gdi::VirtualScreen::updatePalette(g_systemPalette); HOOK_FUNCTION(gdi32, GetSystemPaletteEntries, getSystemPaletteEntries); HOOK_FUNCTION(gdi32, GetSystemPaletteUse, getSystemPaletteUse); diff --git a/DDrawCompat/Gdi/VirtualScreen.cpp b/DDrawCompat/Gdi/VirtualScreen.cpp index 06f7255..606b4d4 100644 --- a/DDrawCompat/Gdi/VirtualScreen.cpp +++ b/DDrawCompat/Gdi/VirtualScreen.cpp @@ -1,5 +1,6 @@ #include +#include "Common/ScopedCriticalSection.h" #include "DDraw/DirectDraw.h" #include "DDraw/ScopedThreadLock.h" #include "DDraw/Surfaces/PrimarySurface.h" @@ -10,6 +11,7 @@ namespace { + Compat::CriticalSection g_cs; Gdi::Region g_region; RECT g_bounds = {}; DWORD g_bpp = 0; @@ -70,7 +72,7 @@ namespace Gdi { HDC createDc() { - DDraw::ScopedThreadLock lock; + Compat::ScopedCriticalSection lock(g_cs); std::unique_ptr dib(createDib(), DeleteObject); if (!dib) { @@ -91,7 +93,6 @@ namespace Gdi dib.release(); - g_stockBitmap = stockBitmap; g_dcs.insert(dc.get()); return dc.release(); @@ -99,7 +100,7 @@ namespace Gdi HBITMAP createDib() { - DDraw::ScopedThreadLock lock; + Compat::ScopedCriticalSection lock(g_cs); if (!g_surfaceFileMapping) { return nullptr; @@ -109,19 +110,21 @@ namespace Gdi HBITMAP createOffScreenDib(DWORD width, DWORD height) { - DDraw::ScopedThreadLock lock; + Compat::ScopedCriticalSection lock(g_cs); return createDibSection(width, height, nullptr); } CompatPtr createSurface(const RECT& rect) { + DDraw::ScopedThreadLock ddLock; + Compat::ScopedCriticalSection lock(g_cs); + if (rect.left < g_bounds.left || rect.top < g_bounds.top || rect.right > g_bounds.right || rect.bottom > g_bounds.bottom) { return nullptr; } - DDraw::ScopedThreadLock lock; DDSURFACEDESC2 desc = {}; desc.dwSize = sizeof(desc); desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS | DDSD_PITCH | DDSD_LPSURFACE; @@ -151,7 +154,7 @@ namespace Gdi return; } - DDraw::ScopedThreadLock lock; + Compat::ScopedCriticalSection lock(g_cs); DeleteObject(SelectObject(dc, g_stockBitmap)); DeleteDC(dc); g_dcs.erase(dc); @@ -159,13 +162,13 @@ namespace Gdi RECT getBounds() { - DDraw::ScopedThreadLock lock; + Compat::ScopedCriticalSection lock(g_cs); return g_bounds; } - const Region& getRegion() + Region getRegion() { - DDraw::ScopedThreadLock lock; + Compat::ScopedCriticalSection lock(g_cs); return g_region; } @@ -177,7 +180,7 @@ namespace Gdi bool update() { LOG_FUNC("VirtualScreen::update"); - DDraw::ScopedThreadLock lock; + Compat::ScopedCriticalSection lock(g_cs); static auto prevDisplaySettingsUniqueness = Win32::DisplayMode::queryDisplaySettingsUniqueness() - 1; const auto currentDisplaySettingsUniqueness = Win32::DisplayMode::queryDisplaySettingsUniqueness(); @@ -220,19 +223,16 @@ namespace Gdi return LOG_RESULT(true); } - void updatePalette() + void updatePalette(PALETTEENTRY(&palette)[256]) { - DDraw::ScopedThreadLock lock; - - PALETTEENTRY pal[256] = {}; - GetSystemPaletteEntries(Gdi::getScreenDc(), 0, 256, pal); + Compat::ScopedCriticalSection lock(g_cs); RGBQUAD systemPalette[256] = {}; for (int i = 0; i < 256; ++i) { - systemPalette[i].rgbRed = pal[i].peRed; - systemPalette[i].rgbGreen = pal[i].peGreen; - systemPalette[i].rgbBlue = pal[i].peBlue; + systemPalette[i].rgbRed = palette[i].peRed; + systemPalette[i].rgbGreen = palette[i].peGreen; + systemPalette[i].rgbBlue = palette[i].peBlue; } if (0 != memcmp(g_systemPalette, systemPalette, sizeof(systemPalette))) diff --git a/DDrawCompat/Gdi/VirtualScreen.h b/DDrawCompat/Gdi/VirtualScreen.h index 9ac4dfb..3fa85cc 100644 --- a/DDrawCompat/Gdi/VirtualScreen.h +++ b/DDrawCompat/Gdi/VirtualScreen.h @@ -19,10 +19,10 @@ namespace Gdi void deleteDc(HDC dc); RECT getBounds(); - const Region& getRegion(); + Region getRegion(); void init(); bool update(); - void updatePalette(); + void updatePalette(PALETTEENTRY(&palette)[256]); } }