windows-nt/Source/XPSP1/NT/multimedia/directx/dplay/dnet/common/readwritelock.cpp
2020-09-26 16:20:57 +08:00

221 lines
3.5 KiB
C++

// ReadWriteLock.cpp: implementation of the CReadWriteLock class.
//
//////////////////////////////////////////////////////////////////////
#include "dncmni.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
#undef DPF_MODNAME
#define DPF_MODNAME "CReadWriteLock::CReadWriteLock"
CReadWriteLock::CReadWriteLock() :
m_hReadSem(0),
m_hWriteSem(0),
m_nReaderWaitingCount(0),
m_nWriterWaitingCount(0),
m_nActiveCount(0),
m_fCritSecInited(FALSE)
#ifdef DEBUG
,m_dwWriteThread(0)
#endif
{
DPF_ENTER();
DPF_EXIT();
}
#undef DPF_MODNAME
#define DPF_MODNAME "CReadWriteLock::~CReadWriteLock"
CReadWriteLock::~CReadWriteLock()
{
DPF_ENTER();
DNASSERT(m_nActiveCount == 0);
if (m_fCritSecInited)
{
DNDeleteCriticalSection(&m_csWrite);
}
if (m_hReadSem)
{
CloseHandle(m_hReadSem);
}
if (m_hWriteSem)
{
CloseHandle(m_hWriteSem);
}
DPF_EXIT();
}
#undef DPF_MODNAME
#define DPF_MODNAME "CReadWriteLock::Init"
BOOL CReadWriteLock::Init()
{
DPF_ENTER();
// Core will attempt to initialize us multiple times, just take the first
if (!m_fCritSecInited)
{
m_hReadSem = CreateSemaphore(0,0,MAXLONG,0);
if (!m_hReadSem)
{
goto error;
}
m_hWriteSem = CreateSemaphore(0,0,MAXLONG,0);
if (!m_hWriteSem)
{
goto error;
}
if (!DNInitializeCriticalSection(&m_csWrite))
{
goto error;
}
m_fCritSecInited = TRUE;
}
DPF_EXIT();
return TRUE;
error:
if (m_hReadSem)
{
CloseHandle(m_hReadSem);
m_hReadSem = 0;
}
if (m_hWriteSem)
{
CloseHandle(m_hWriteSem);
m_hWriteSem = 0;
}
DPF_EXIT();
return FALSE;
}
#undef DPF_MODNAME
#define DPF_MODNAME "CReadWriteLock::EnterReadLock"
void CReadWriteLock::EnterReadLock()
{
DPF_ENTER();
DNASSERT(m_fCritSecInited);
DNEnterCriticalSection(&m_csWrite);
// If there is a Writer writing or waiting to write, they have priority
BOOL fWaitOnWriters = (m_nWriterWaitingCount || (m_nActiveCount < 0));
if (fWaitOnWriters)
{
m_nReaderWaitingCount++;
}
else
{
m_nActiveCount++;
}
DNLeaveCriticalSection(&m_csWrite);
if (fWaitOnWriters)
{
WaitForSingleObject(m_hReadSem, INFINITE);
}
DPF_EXIT();
}
#undef DPF_MODNAME
#define DPF_MODNAME "CReadWriteLock::LeaveLock"
void CReadWriteLock::LeaveLock()
{
DPF_ENTER();
DNASSERT(m_fCritSecInited);
DNEnterCriticalSection(&m_csWrite);
if (m_nActiveCount > 0)
{
m_nActiveCount--;
}
else
{
DEBUG_ONLY(m_dwWriteThread = 0);
m_nActiveCount++;
}
HANDLE hSem = 0;
LONG lCount = 1;
if (m_nActiveCount == 0)
{
if (m_nWriterWaitingCount > 0)
{
m_nActiveCount = -1;
m_nWriterWaitingCount--;
hSem = m_hWriteSem;
}
else if (m_nReaderWaitingCount > 0)
{
m_nActiveCount = m_nReaderWaitingCount;
m_nReaderWaitingCount = 0;
hSem = m_hReadSem;
lCount = m_nActiveCount;
}
}
DNLeaveCriticalSection(&m_csWrite);
if (hSem)
{
ReleaseSemaphore(hSem, lCount, 0);
}
DPF_EXIT();
}
#undef DPF_MODNAME
#define DPF_MODNAME "CReadWriteLock::EnterWriteLock"
void CReadWriteLock::EnterWriteLock()
{
DPF_ENTER();
DNASSERT(m_fCritSecInited);
DNEnterCriticalSection(&m_csWrite);
BOOL fAvailable = (m_nActiveCount == 0);
if (fAvailable)
{
m_nActiveCount = -1;
}
else
{
DNASSERT(m_dwWriteThread != GetCurrentThreadId()); // No re-entrance!
m_nWriterWaitingCount++;
}
DNLeaveCriticalSection(&m_csWrite);
if (!fAvailable)
{
WaitForSingleObject(m_hWriteSem, INFINITE);
}
DEBUG_ONLY(m_dwWriteThread = GetCurrentThreadId());
DPF_EXIT();
}