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.
578 lines
12 KiB
578 lines
12 KiB
/*++
|
|
|
|
Copyright (C) Microsoft Corporation, 1996 - 1999
|
|
|
|
Module Name:
|
|
|
|
Locks
|
|
|
|
Abstract:
|
|
|
|
This module provides the definitions of common lock objects.
|
|
|
|
Author:
|
|
|
|
Doug Barlow (dbarlow) 10/24/1996
|
|
|
|
Environment:
|
|
|
|
Win32, C++ w/ exceptions
|
|
|
|
Notes:
|
|
|
|
?Notes?
|
|
|
|
--*/
|
|
|
|
#ifndef _LOCKS_H_
|
|
#define _LOCKS_H_
|
|
|
|
#ifdef DBG
|
|
#define REASONABLE_TIME 2 * 60 * 1000 // Two minutes
|
|
#else
|
|
#define REASONABLE_TIME INFINITE
|
|
#endif
|
|
|
|
extern DWORD
|
|
WaitForAnyObject(
|
|
DWORD dwTimeout,
|
|
...);
|
|
|
|
extern DWORD
|
|
WaitForAnObject(
|
|
HANDLE hWaitOn,
|
|
DWORD dwTimeout);
|
|
|
|
#ifdef DBG
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ TEXT("WaitForEverObject")
|
|
|
|
inline void
|
|
WaitForEverObject(
|
|
HANDLE hWaitOn,
|
|
DWORD dwTimeout,
|
|
DEBUG_TEXT szReason,
|
|
LPCTSTR szObject = NULL)
|
|
{
|
|
DWORD dwSts;
|
|
while (ERROR_SUCCESS != (dwSts = WaitForAnObject(hWaitOn, dwTimeout)))
|
|
CalaisWarning(__SUBROUTINE__, szReason, dwSts, szObject);
|
|
}
|
|
inline void
|
|
WaitForEverObject(
|
|
HANDLE hWaitOn,
|
|
DWORD dwTimeout,
|
|
DEBUG_TEXT szReason,
|
|
DWORD dwObject)
|
|
{
|
|
DWORD dwSts;
|
|
TCHAR szNum[16];
|
|
|
|
wsprintf(szNum, TEXT("0x%08x"), dwObject);
|
|
while (ERROR_SUCCESS != (dwSts = WaitForAnObject(hWaitOn, dwTimeout)))
|
|
CalaisWarning(__SUBROUTINE__, szReason, dwSts, szNum);
|
|
}
|
|
#define WaitForever(hWaitOn, dwTimeout, szReason, szObject) \
|
|
WaitForEverObject(hWaitOn, dwTimeout, szReason, szObject)
|
|
|
|
#else
|
|
|
|
inline void
|
|
WaitForEverObject(
|
|
HANDLE hWaitOn)
|
|
{
|
|
while (ERROR_SUCCESS != WaitForAnObject(hWaitOn, INFINITE));
|
|
// Empty body
|
|
}
|
|
#define WaitForever(hWaitOn, dwTimeout, szReason, szObject) \
|
|
WaitForEverObject(hWaitOn)
|
|
|
|
#endif
|
|
|
|
|
|
//
|
|
// Critical Section Support.
|
|
//
|
|
// The following Classes and Macros aid in debugging Critical Section
|
|
// Conflicts.
|
|
//
|
|
|
|
|
|
//
|
|
//==============================================================================
|
|
//
|
|
// CCriticalSectionObject
|
|
//
|
|
|
|
class CCriticalSectionObject
|
|
{
|
|
public:
|
|
|
|
// Constructors & Destructor
|
|
CCriticalSectionObject(DWORD dwCsid = 0);
|
|
~CCriticalSectionObject();
|
|
|
|
// Properties
|
|
// Methods
|
|
virtual void Enter(DEBUG_TEXT szOwner, DEBUG_TEXT szComment);
|
|
virtual void Leave(void);
|
|
|
|
#ifdef DBG
|
|
LPCTSTR Description(void) const;
|
|
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ TEXT("CCriticalSectionObject::Owner")
|
|
LPCTSTR Owner(void) const
|
|
{ return (LPCTSTR)m_bfOwner.Access(); };
|
|
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ TEXT("CCriticalSectionObject::Comment")
|
|
LPCTSTR Comment(void) const
|
|
{ return (LPCTSTR)m_bfComment.Access(); };
|
|
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ TEXT("CCriticalSectionObject::IsOwnedByMe")
|
|
BOOL IsOwnedByMe(void) const
|
|
{ return (GetCurrentThreadId() == m_dwOwnerThread); };
|
|
#endif
|
|
// Operators
|
|
|
|
protected:
|
|
// Properties
|
|
CRITICAL_SECTION m_csLock;
|
|
#ifdef DBG
|
|
DWORD m_dwCsid;
|
|
CBuffer m_bfOwner;
|
|
CBuffer m_bfComment;
|
|
DWORD m_dwOwnerThread;
|
|
DWORD m_dwRecursion;
|
|
DWORD m_dwArrayEntry;
|
|
static CDynamicArray<CCriticalSectionObject *> *mg_prgCSObjects;
|
|
static CRITICAL_SECTION mg_csArrayLock;
|
|
#endif
|
|
|
|
// Methods
|
|
};
|
|
|
|
|
|
//
|
|
//==============================================================================
|
|
//
|
|
// COwnCriticalSection
|
|
//
|
|
|
|
class COwnCriticalSection
|
|
{
|
|
public:
|
|
|
|
// Constructors & Destructor
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ TEXT("COwnCriticalSection::COwnCriticalSection")
|
|
COwnCriticalSection(
|
|
CCriticalSectionObject *pcs,
|
|
DEBUG_TEXT szSubroutine,
|
|
DEBUG_TEXT szComment)
|
|
{
|
|
m_pcsLock = pcs;
|
|
m_pcsLock->Enter(szSubroutine, szComment);
|
|
};
|
|
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ TEXT("COwnCriticalSection::~COwnCriticalSection")
|
|
~COwnCriticalSection()
|
|
{
|
|
m_pcsLock->Leave();
|
|
};
|
|
|
|
// Properties
|
|
// Methods
|
|
// Operators
|
|
|
|
protected:
|
|
// Properties
|
|
CCriticalSectionObject *m_pcsLock;
|
|
|
|
// Methods
|
|
};
|
|
|
|
#define LockSection(cx, reason) \
|
|
COwnCriticalSection csLock(cx, __SUBROUTINE__, reason)
|
|
|
|
#ifndef DBG
|
|
|
|
//
|
|
//In-line the simple Critical Section calls.
|
|
//
|
|
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ TEXT("CCriticalSectionObject::CCriticalSectionObject")
|
|
inline
|
|
CCriticalSectionObject::CCriticalSectionObject(
|
|
DWORD dwCsid)
|
|
{
|
|
BOOL fInited = FALSE;
|
|
|
|
do
|
|
{
|
|
try
|
|
{
|
|
InitializeCriticalSection(&m_csLock);
|
|
fInitied = TRUE;
|
|
}
|
|
catch (...)
|
|
{
|
|
Sleep(1000); // Sleep for 1 second.
|
|
}
|
|
} while (!fInited);
|
|
}
|
|
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ TEXT("CCriticalSectionObject::~CCriticalSectionObject")
|
|
inline
|
|
CCriticalSectionObject::~CCriticalSectionObject()
|
|
{
|
|
DeleteCriticalSection(&m_csLock);
|
|
}
|
|
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ TEXT("CCriticalSectionObject::Enter")
|
|
inline void
|
|
CCriticalSectionObject::Enter(
|
|
DEBUG_TEXT szOwner,
|
|
DEBUG_TEXT szComment)
|
|
{
|
|
BOOL fEntered = FALSE;
|
|
|
|
do
|
|
{
|
|
try
|
|
{
|
|
EnterCriticalSection(&m_csLock);
|
|
fEntered = TRUE;
|
|
}
|
|
catch (...)
|
|
{
|
|
Sleep(1000); // Sleep for 1 second.
|
|
}
|
|
} while (!fEntered);
|
|
}
|
|
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ TEXT("CCriticalSectionObject::Leave")
|
|
inline void
|
|
CCriticalSectionObject::Leave(
|
|
void)
|
|
{
|
|
LeaveCriticalSection(&m_csLock);
|
|
}
|
|
|
|
#endif // !DBG
|
|
|
|
|
|
//
|
|
//==============================================================================
|
|
//
|
|
// CHandleObject
|
|
//
|
|
|
|
class CHandleObject
|
|
{
|
|
public:
|
|
|
|
// Constructors & Destructor
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ TEXT("CHandleObject::CHandleObject")
|
|
CHandleObject(DEBUG_TEXT szName)
|
|
#ifdef DBG
|
|
: m_bfName((LPCBYTE)szName, (lstrlen(szName) + 1) * sizeof(TCHAR))
|
|
#endif
|
|
{
|
|
m_hHandle = NULL;
|
|
m_dwError = ERROR_SUCCESS;
|
|
};
|
|
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ TEXT("CHandleObject::~CHandleObject")
|
|
~CHandleObject()
|
|
{
|
|
if (IsValid())
|
|
{
|
|
#ifdef _DEBUG
|
|
CalaisWarning(
|
|
__SUBROUTINE__,
|
|
DBGT("Unclosed handle '%1' -- fixing."),
|
|
(DEBUG_TEXT)m_bfName.Access());
|
|
#endif
|
|
Close();
|
|
}
|
|
};
|
|
|
|
// Properties
|
|
// Methods
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ TEXT("CHandleObject::IsValid")
|
|
BOOL IsValid(void) const
|
|
{
|
|
return (NULL != m_hHandle) && (INVALID_HANDLE_VALUE != m_hHandle);
|
|
};
|
|
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ TEXT("CHandleObject::Value")
|
|
HANDLE Value(void) const
|
|
{
|
|
#ifdef _DEBUG
|
|
if (!IsValid())
|
|
CalaisWarning(
|
|
__SUBROUTINE__,
|
|
DBGT("Accessing invalid '%1' handle value."),
|
|
(DEBUG_TEXT)m_bfName.Access());
|
|
#endif
|
|
return m_hHandle;
|
|
};
|
|
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ TEXT("CHandleObject::GetLastError")
|
|
DWORD GetLastError(void) const
|
|
{
|
|
return m_dwError;
|
|
};
|
|
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ TEXT("CHandleObject::Open")
|
|
HANDLE Open(HANDLE h)
|
|
{
|
|
if ((NULL == h) || (INVALID_HANDLE_VALUE == h))
|
|
{
|
|
m_dwError = ::GetLastError();
|
|
#ifdef _DEBUG
|
|
CalaisWarning(
|
|
__SUBROUTINE__,
|
|
DBGT("Attempt to assign invalid handle value to '%1'."),
|
|
(DEBUG_TEXT)m_bfName.Access());
|
|
#endif
|
|
}
|
|
else
|
|
m_dwError = ERROR_SUCCESS;
|
|
if (IsValid())
|
|
{
|
|
#ifdef _DEBUG
|
|
CalaisWarning(
|
|
__SUBROUTINE__,
|
|
DBGT("Overwriting handle '%1' -- fixing"),
|
|
(DEBUG_TEXT)m_bfName.Access());
|
|
#endif
|
|
Close();
|
|
}
|
|
m_hHandle = h;
|
|
return m_hHandle;
|
|
};
|
|
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ TEXT("CHandleObject::Close")
|
|
DWORD Close(void)
|
|
{
|
|
DWORD dwSts = ERROR_SUCCESS;
|
|
|
|
if (IsValid())
|
|
{
|
|
BOOL fSts;
|
|
|
|
fSts = CloseHandle(m_hHandle);
|
|
#ifdef DBG
|
|
if (!fSts)
|
|
{
|
|
dwSts = GetLastError();
|
|
CalaisWarning(
|
|
__SUBROUTINE__,
|
|
DBGT("Failed to close handle '%2': %1"),
|
|
dwSts,
|
|
(DEBUG_TEXT)m_bfName.Access());
|
|
}
|
|
#endif
|
|
m_hHandle = NULL;
|
|
}
|
|
#ifdef DBG
|
|
else
|
|
{
|
|
CalaisWarning(
|
|
__SUBROUTINE__,
|
|
DBGT("Attempt to re-close handle '%1'"),
|
|
(DEBUG_TEXT)m_bfName.Access());
|
|
}
|
|
#endif
|
|
return dwSts;
|
|
};
|
|
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ TEXT("CHandleObject::Relinquish")
|
|
HANDLE Relinquish(void)
|
|
{
|
|
HANDLE hTmp = m_hHandle;
|
|
#ifdef _DEBUG
|
|
if (!IsValid())
|
|
CalaisWarning(
|
|
__SUBROUTINE__,
|
|
DBGT("Relinquishing invalid '%1' handle"),
|
|
(DEBUG_TEXT)m_bfName.Access());
|
|
#endif
|
|
m_hHandle = NULL;
|
|
return hTmp;
|
|
};
|
|
|
|
// Operators
|
|
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ TEXT("CHandleObject::operator HANDLE")
|
|
operator HANDLE(void) const
|
|
{
|
|
ASSERT(IsValid());
|
|
return Value();
|
|
};
|
|
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ TEXT("CHandleObject::operator=")
|
|
HANDLE operator=(HANDLE h)
|
|
{
|
|
return Open(h);
|
|
};
|
|
|
|
protected:
|
|
// Properties
|
|
HANDLE m_hHandle;
|
|
DWORD m_dwError;
|
|
#ifdef DBG
|
|
CBuffer m_bfName;
|
|
#endif
|
|
|
|
// Methods
|
|
};
|
|
|
|
|
|
//
|
|
//==============================================================================
|
|
//
|
|
// CAccessLock
|
|
//
|
|
|
|
class CAccessLock
|
|
{
|
|
public:
|
|
// Constructors & Destructor
|
|
|
|
CAccessLock(DWORD dwTimeout = CALAIS_LOCK_TIMEOUT);
|
|
~CAccessLock();
|
|
|
|
#ifdef DBG
|
|
BOOL NotReadLocked(void);
|
|
BOOL IsReadLocked(void);
|
|
BOOL NotWriteLocked(void);
|
|
BOOL IsWriteLocked(void);
|
|
#endif
|
|
|
|
protected:
|
|
// Properties
|
|
|
|
CCriticalSectionObject m_csLock;
|
|
DWORD m_dwReadCount;
|
|
DWORD m_dwWriteCount;
|
|
DWORD m_dwTimeout;
|
|
CHandleObject m_hSignalNoReaders;
|
|
CHandleObject m_hSignalNoWriters;
|
|
DWORD m_dwOwner;
|
|
#ifdef DBG
|
|
CDynamicArray<VOID> m_rgdwReaders;
|
|
#endif
|
|
|
|
|
|
// Methods
|
|
|
|
void Wait(HANDLE hSignal);
|
|
void Signal(HANDLE hSignal);
|
|
void Unsignal(HANDLE hSignal);
|
|
|
|
void WaitOnReaders(void)
|
|
{
|
|
Wait(m_hSignalNoReaders);
|
|
};
|
|
void WaitOnWriters(void)
|
|
{
|
|
Wait(m_hSignalNoWriters);
|
|
};
|
|
void SignalNoReaders(void)
|
|
{
|
|
Signal(m_hSignalNoReaders);
|
|
};
|
|
void SignalNoWriters(void)
|
|
{
|
|
Signal(m_hSignalNoWriters);
|
|
};
|
|
void UnsignalNoReaders(void)
|
|
{
|
|
Signal(m_hSignalNoReaders);
|
|
};
|
|
void UnsignalNoWriters(void)
|
|
{
|
|
Unsignal(m_hSignalNoWriters);
|
|
};
|
|
|
|
friend class CLockRead;
|
|
friend class CLockWrite;
|
|
};
|
|
|
|
|
|
//
|
|
//==============================================================================
|
|
//
|
|
// CLockRead
|
|
//
|
|
|
|
class CLockRead
|
|
{
|
|
public:
|
|
|
|
// Constructors & Destructor
|
|
CLockRead(CAccessLock *pLock);
|
|
~CLockRead();
|
|
|
|
// Properties
|
|
// Methods
|
|
// Operators
|
|
|
|
protected:
|
|
// Properties
|
|
CAccessLock * m_pLock;
|
|
|
|
// Methods
|
|
};
|
|
|
|
|
|
//
|
|
//==============================================================================
|
|
//
|
|
// CLockWrite
|
|
//
|
|
|
|
class CLockWrite
|
|
{
|
|
public:
|
|
|
|
// Constructors & Destructor
|
|
|
|
CLockWrite(CAccessLock *pLock);
|
|
~CLockWrite();
|
|
|
|
// Properties
|
|
// Methods
|
|
// Operators
|
|
|
|
protected:
|
|
// Properties
|
|
|
|
CAccessLock *m_pLock;
|
|
|
|
|
|
// Methods
|
|
};
|
|
|
|
#endif // _LOCKS_H_
|
|
|