1
0
mirror of https://github.com/narzoul/DDrawCompat synced 2024-12-30 08:55:36 +01:00

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.
This commit is contained in:
narzoul 2016-04-17 21:13:16 +02:00
parent cc5a4c7cef
commit 74f306b5b0

View File

@ -1,5 +1,3 @@
#include <atomic>
#include "CompatDirectDrawPalette.h" #include "CompatDirectDrawPalette.h"
#include "CompatDirectDrawSurface.h" #include "CompatDirectDrawSurface.h"
#include "CompatGdi.h" #include "CompatGdi.h"
@ -17,7 +15,7 @@
namespace namespace
{ {
std::atomic<DWORD> g_renderingRefCount = 0; DWORD g_renderingRefCount = 0;
DWORD g_ddLockThreadRenderingRefCount = 0; DWORD g_ddLockThreadRenderingRefCount = 0;
DWORD g_ddLockThreadId = 0; DWORD g_ddLockThreadId = 0;
HANDLE g_ddUnlockBeginEvent = nullptr; HANDLE g_ddUnlockBeginEvent = nullptr;
@ -93,21 +91,19 @@ namespace CompatGdi
return false; return false;
} }
Compat::ScopedCriticalSection gdiLock(g_gdiCriticalSection);
if (0 == g_renderingRefCount) if (0 == g_renderingRefCount)
{ {
LeaveCriticalSection(&g_gdiCriticalSection);
Compat::origProcs.AcquireDDThreadLock(); Compat::origProcs.AcquireDDThreadLock();
EnterCriticalSection(&g_gdiCriticalSection); EnterCriticalSection(&g_gdiCriticalSection);
if (!lockPrimarySurface()) if (!lockPrimarySurface())
{ {
LeaveCriticalSection(&g_gdiCriticalSection);
Compat::origProcs.ReleaseDDThreadLock(); Compat::origProcs.ReleaseDDThreadLock();
return false; return false;
} }
} }
else
{
EnterCriticalSection(&g_gdiCriticalSection);
}
if (GetCurrentThreadId() == g_ddLockThreadId) if (GetCurrentThreadId() == g_ddLockThreadId)
{ {
@ -115,13 +111,12 @@ namespace CompatGdi
} }
++g_renderingRefCount; ++g_renderingRefCount;
LeaveCriticalSection(&g_gdiCriticalSection);
return true; return true;
} }
void endGdiRendering() void endGdiRendering()
{ {
Compat::ScopedCriticalSection gdiLock(CompatGdi::g_gdiCriticalSection); Compat::ScopedCriticalSection gdiLock(g_gdiCriticalSection);
if (GetCurrentThreadId() == g_ddLockThreadId) if (GetCurrentThreadId() == g_ddLockThreadId)
{ {