Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

435 lines
11 KiB

/*++
Copyright (C) 1996-2001 Microsoft Corporation
Module Name:
LOCK.CPP
Abstract:
Implements the generic class for obtaining read and write locks to some
resource.
See lock.h for all documentation.
Classes defined:
CLock
History:
a-levn 5-Sept-96 Created.
3/10/97 a-levn Fully documented
--*/
#include <windows.h>
#include <ole2.h>
#include <stdio.h>
#include <stdio.h>
#include "lock.h"
// debugging.
#define PRINTF
#if 0
#define DBG_PRINTFA( a ) { char pBuff[128]; sprintf a ; OutputDebugStringA(pBuff); }
#else
#define DBG_PRINTFA( a )
#endif
//******************************************************************************
//
// See lock.h for documentation
//
//******************************************************************************
CLock::CLock() : m_nReading(0), m_nWriting(0), m_nWaitingToRead(0),
m_nWaitingToWrite(0),
m_csEntering(THROW_LOCK,0x80000000 | 500L),
m_csAll(THROW_LOCK,0x80000000 | 500L)
{
m_dwArrayIndex = 0;
for (DWORD i=0;i<MaxRegistredReaders;i++)
{
m_adwReaders[i].ThreadId = 0;
}
// Create unnamed events for reading and writing
// =============================================
m_hCanRead = CreateEvent(NULL, TRUE, TRUE, NULL);
m_hCanWrite = CreateEvent(NULL, TRUE, TRUE, NULL);
if (NULL == m_hCanRead || NULL == m_hCanWrite)
DebugBreak();
}
//******************************************************************************
//
// See lock.h for documentation
//
//******************************************************************************
CLock::~CLock()
{
CloseHandle(m_hCanWrite);
CloseHandle(m_hCanRead);
}
//******************************************************************************
//
// See lock.h for documentation
//
//******************************************************************************
int CLock::ReadLock(DWORD dwTimeout)
{
PRINTF("%d wants to read\n", GetCurrentThreadId());
// Get in line for getting any kind of lock (those unlocking don't go into
// this line)
// =======================================================================
DWORD_PTR dwThreadId = GetCurrentThreadId();
LockGuard<CriticalSection> lgEnter(m_csEntering);
if (!lgEnter.locked())
{
DebugBreak();
return TimedOut;
}
// We are the only ones allowed to get any kind of lock now. Wait for the
// event indicating that reading is enabled to become signaled
// ======================================================================
PRINTF("%d next to enter\n", GetCurrentThreadId());
if(m_nWriting != 0)
{
int nRes = WaitFor(m_hCanRead, dwTimeout);
if(nRes != NoError)
{
return nRes;
}
}
// Enter inner critical section (unlockers use it too), increment the
// number of readers and disable writing.
// ==================================================================
PRINTF("%d got event\n", GetCurrentThreadId());
LockGuard<CriticalSection> lgAll(m_csAll);
if (!lgAll.locked())
{
if(m_nReading == 0)
{
// this is for the read lock acquired on one thread and release on one other
m_dwArrayIndex = 0;
if(!SetEvent(m_hCanWrite))
{
DebugBreak();
return Failed;
}
}
DebugBreak();
return TimedOut;
}
m_nReading++;
DBG_PRINTFA((pBuff,"+ (%08x) %d\n",GetCurrentThreadId(),m_nReading));
if (m_dwArrayIndex < MaxRegistredReaders)
{
m_adwReaders[m_dwArrayIndex].ThreadId = dwThreadId;
ULONG Hash;
//RtlCaptureStackBackTrace(1,MaxTraceSize,m_adwReaders[m_dwArrayIndex].Trace,&Hash);
m_dwArrayIndex++;
}
//m_adwReaders.Add((void*)dwThreadId);
PRINTF("Reset write\n");
ResetEvent(m_hCanWrite);
PRINTF("Done\n");
if (m_nWriting)
{
//OutputDebugString(L"WinMgmt: Read lock aquired while write lock is aquired!\n");
DebugBreak();
}
// Get out of all critical sections and return
// ===========================================
PRINTF("%d begins to read\n", GetCurrentThreadId());
return NoError;
}
//******************************************************************************
//
// See lock.h for documentation
//
//******************************************************************************
int CLock::ReadUnlock()
{
PRINTF("%d wants to unlock reading\n", GetCurrentThreadId());
// Enter internal ciritcal section and decrement the number of readers
// ===================================================================
LockGuard<CriticalSection> gl(m_csAll);
while (!gl.locked())
{
Sleep(20);
gl.acquire();
};
m_nReading--;
DBG_PRINTFA((pBuff,"- (%08x) %d\n",GetCurrentThreadId(),m_nReading));
if(m_nReading < 0)
{
//OutputDebugString(L"WinMgmt: Repository detected more read unlocks than locks\n");
DebugBreak();
return Failed;
}
DWORD_PTR dwThreadId = GetCurrentThreadId();
for(int i = 0; i < MaxRegistredReaders; i++)
{
if(m_adwReaders[i].ThreadId == dwThreadId)
{
m_adwReaders[i].ThreadId = 0;
break;
}
}
// If all readers are gone, allow writers in
// =========================================
if(m_nReading == 0)
{
// this is for the read lock acquired on one thread and release on one other
m_dwArrayIndex = 0;
PRINTF("%d is the last reader\n", GetCurrentThreadId());
PRINTF("Set write\n");
if(!SetEvent(m_hCanWrite))
{
DebugBreak();
return Failed;
}
PRINTF("Done\n");
}
else PRINTF("%d sees %d still reading\n", GetCurrentThreadId(), m_nReading);
// Get out and return
// ==================
return NoError;
}
//******************************************************************************
//
// See lock.h for documentation
//
//******************************************************************************
int CLock::WriteLock(DWORD dwTimeout)
{
PRINTF("%d wants to write\n", GetCurrentThreadId());
// Get in line for getting any kind of lock. Those unlocking don't use this
// critical section.
// ========================================================================
LockGuard<CriticalSection> lgEnter(m_csEntering);
if (!lgEnter.locked())
{
DebugBreak();
return TimedOut;
}
// We are the only ones allowed to get any kind of lock now
// ========================================================
PRINTF("%d next to enter\n", GetCurrentThreadId());
// Wait for the event allowing writing to become signaled
// ======================================================
int nRes = WaitFor(m_hCanWrite, dwTimeout);
PRINTF("%d got event\n", GetCurrentThreadId());
if(nRes != NoError)
{
DebugBreak();
return nRes;
}
// Enter internal critical section (unlockers use it too), increment the
// number of writers (from 0 to 1) and disable both reading and writing
// from now on.
// ======================================================================
LockGuard<CriticalSection> lgAll(m_csAll);
if (!lgAll.locked())
{
if(!SetEvent(m_hCanWrite))
DebugBreak();
DebugBreak();
return TimedOut;
}
m_WriterId = GetCurrentThreadId();
m_nWriting++;
DBG_PRINTFA((pBuff,"+ (%08x) %d W %d\n",GetCurrentThreadId(),m_nReading,m_nWriting));
PRINTF("Reset both\n");
ResetEvent(m_hCanWrite);
ResetEvent(m_hCanRead);
PRINTF("Done\n");
if (m_nReading)
{
//OutputDebugString(L"WinMgmt: Write lock aquired while read lock is aquired!\n");
DebugBreak();
}
// Get out and return
// ==================
PRINTF("%d begins to write\n", GetCurrentThreadId());
return NoError;
}
//******************************************************************************
//
// See lock.h for documentation
//
//******************************************************************************
int CLock::WriteUnlock()
{
PRINTF("%d wants to release writing\n", GetCurrentThreadId());
// Enter lock determination critical section
// =========================================
LockGuard<CriticalSection> gl(m_csAll);
while (!gl.locked())
{
Sleep(20);
gl.acquire();
};
m_nWriting--;
DBG_PRINTFA((pBuff,"- (%08x) %d W %d\n",GetCurrentThreadId(),m_nReading,m_nWriting));
m_WriterId = 0;
if(m_nWriting < 0)
{
//OutputDebugString(L"WinMgmt: Repository detected too many write unlocks\n");
DebugBreak();
return Failed;
}
// Allow readers and writers in
// ============================
PRINTF("%d released writing\n", GetCurrentThreadId());
PRINTF("Set both\n");
if(!SetEvent(m_hCanRead))
{
DebugBreak();
return Failed;
}
else if(!SetEvent(m_hCanWrite))
{
DebugBreak();
return Failed;
}
else
{
PRINTF("Done\n");
return NoError;
}
}
//******************************************************************************
//
// See lock.h for documentation
//
//******************************************************************************
int CLock::WaitFor(HANDLE hEvent, DWORD dwTimeout)
{
DWORD dwRes;
dwRes = WaitForSingleObject(hEvent, dwTimeout);
// Analyze the error code and convert to ours
// ==========================================
if(dwRes == WAIT_OBJECT_0) return NoError;
else if(dwRes == WAIT_TIMEOUT) return TimedOut;
else return Failed;
}
//******************************************************************************
//
// See lock.h for documentation
//
//******************************************************************************
int CLock::DowngradeLock()
{
// Enter lock determination critical section
// =========================================
LockGuard<CriticalSection> gl(m_csAll);
while (!gl.locked())
{
Sleep(20);
gl.acquire();
};
m_nWriting--;
m_WriterId = 0;
if(!SetEvent(m_hCanRead))
{
DebugBreak();
return Failed;
}
m_nReading++;
if (1 != m_nReading)
DebugBreak();
DBG_PRINTFA((pBuff,"+ (%08x) %d\n",GetCurrentThreadId(),m_nReading));
DWORD_PTR dwThreadId = GetCurrentThreadId();
if (m_dwArrayIndex < MaxRegistredReaders)
{
m_adwReaders[m_dwArrayIndex].ThreadId = dwThreadId;
ULONG Hash;
//RtlCaptureStackBackTrace(1,MaxTraceSize,m_adwReaders[m_dwArrayIndex].Trace,&Hash);
m_dwArrayIndex++;
}
return NoError;
}