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 "CompatDirectDrawSurface.h"
#include "CompatGdi.h"
@ -17,7 +15,7 @@
namespace
{
std::atomic<DWORD> 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)
{