From 74f306b5b0fa873e3af62b865b129db6ffa5c154 Mon Sep 17 00:00:00 2001 From: narzoul Date: Sun, 17 Apr 2016 21:13:16 +0200 Subject: [PATCH] Fixed synchronization issue in beginGdiRendering It's not sufficient to make g_renderingRefCount atomic, because after it is found to be nonzero in beginGdiRendering, a call to endGdiRendering from another thread may make it zero before beginGdiRendering has a chance of entering the critical section. This would mean that the DirectDraw primary surface is no longer locked, even though beginGdiRendering expects that it is. To prevent potential issues, the g_renderingRefCount check is now also guarded by the critical section. --- DDrawCompat/CompatGdi.cpp | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/DDrawCompat/CompatGdi.cpp b/DDrawCompat/CompatGdi.cpp index 2ac413d..025d934 100644 --- a/DDrawCompat/CompatGdi.cpp +++ b/DDrawCompat/CompatGdi.cpp @@ -1,5 +1,3 @@ -#include - #include "CompatDirectDrawPalette.h" #include "CompatDirectDrawSurface.h" #include "CompatGdi.h" @@ -17,7 +15,7 @@ namespace { - std::atomic g_renderingRefCount = 0; + DWORD g_renderingRefCount = 0; DWORD g_ddLockThreadRenderingRefCount = 0; DWORD g_ddLockThreadId = 0; HANDLE g_ddUnlockBeginEvent = nullptr; @@ -93,21 +91,19 @@ namespace CompatGdi return false; } + Compat::ScopedCriticalSection gdiLock(g_gdiCriticalSection); + if (0 == g_renderingRefCount) { + LeaveCriticalSection(&g_gdiCriticalSection); Compat::origProcs.AcquireDDThreadLock(); EnterCriticalSection(&g_gdiCriticalSection); if (!lockPrimarySurface()) { - LeaveCriticalSection(&g_gdiCriticalSection); Compat::origProcs.ReleaseDDThreadLock(); return false; } } - else - { - EnterCriticalSection(&g_gdiCriticalSection); - } if (GetCurrentThreadId() == g_ddLockThreadId) { @@ -115,13 +111,12 @@ namespace CompatGdi } ++g_renderingRefCount; - LeaveCriticalSection(&g_gdiCriticalSection); return true; } void endGdiRendering() { - Compat::ScopedCriticalSection gdiLock(CompatGdi::g_gdiCriticalSection); + Compat::ScopedCriticalSection gdiLock(g_gdiCriticalSection); if (GetCurrentThreadId() == g_ddLockThreadId) {