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.
864 lines
18 KiB
864 lines
18 KiB
/*++
|
|
|
|
Copyright (C) Microsoft Corporation, 1996 - 1999
|
|
|
|
Module Name:
|
|
|
|
Locks
|
|
|
|
Abstract:
|
|
|
|
The following three classes implement a simple single writer, multiple
|
|
readers lock. CAccessLock is the lock, then the CLockRead and CLockWrite
|
|
objects envoke the lock while they are in scope. They are all implemented
|
|
inline.
|
|
|
|
The CMultiEvent class implements an automatic waitable object that will
|
|
release all threads waiting on it when signaled.
|
|
|
|
Author:
|
|
|
|
Doug Barlow (dbarlow) 10/24/1996
|
|
|
|
Environment:
|
|
|
|
Win32, C++ w/ exceptions
|
|
|
|
Notes:
|
|
|
|
?Notes?
|
|
|
|
--*/
|
|
|
|
#ifndef _LOCKS_H_
|
|
#define _LOCKS_H_
|
|
|
|
#include <WinSCard.h>
|
|
#include "CalMsgs.h"
|
|
#include <SCardLib.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__ DBGT("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.
|
|
//
|
|
|
|
//
|
|
// Critical section Ids. Locks must be obtained in the order from lowest
|
|
// to highest. An attempt to access a lower-numbered lock while holding a
|
|
// higher numbered lock will result in an ASSERT.
|
|
//
|
|
|
|
// Server side lock IDs
|
|
#define CSID_SERVICE_STATUS 0 // Service Status Critical Section
|
|
#define CSID_CONTROL_LOCK 1 // Lock for Calais control commands.
|
|
#define CSID_SERVER_THREADS 2 // Lock for server thread enumeration.
|
|
#define CSID_MULTIEVENT 3 // MultiEvent Critical Access Section
|
|
#define CSID_MUTEX 4 // Mutex critical access section
|
|
#define CSID_ACCESSCONTROL 5 // Access Lock control
|
|
#define CSID_TRACEOUTPUT 6 // Lock for tracing output.
|
|
|
|
// Client side lock IDs
|
|
#define CSID_USER_CONTEXT 0 // User context lock
|
|
#define CSID_SUBCONTEXT 1 // Subcontext lock
|
|
|
|
|
|
//
|
|
//==============================================================================
|
|
//
|
|
// CCriticalSectionObject
|
|
//
|
|
|
|
class CCriticalSectionObject
|
|
{
|
|
public:
|
|
|
|
// Constructors & Destructor
|
|
CCriticalSectionObject(DWORD dwCsid);
|
|
~CCriticalSectionObject();
|
|
|
|
// Properties
|
|
// Methods
|
|
virtual void Enter(DEBUG_TEXT szOwner, DEBUG_TEXT szComment);
|
|
virtual void Leave(void);
|
|
virtual BOOL InitFailed(void) { return m_fInitFailed; }
|
|
|
|
#ifdef DBG
|
|
LPCTSTR Description(void) const;
|
|
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ DBGT("CCriticalSectionObject::Owner")
|
|
LPCTSTR Owner(void) const
|
|
{ return (LPCTSTR)m_bfOwner.Access(); };
|
|
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ DBGT("CCriticalSectionObject::Comment")
|
|
LPCTSTR Comment(void) const
|
|
{ return (LPCTSTR)m_bfComment.Access(); };
|
|
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ DBGT("CCriticalSectionObject::IsOwnedByMe")
|
|
BOOL IsOwnedByMe(void) const
|
|
{ return (GetCurrentThreadId() == m_dwOwnerThread); };
|
|
#endif
|
|
// Operators
|
|
|
|
protected:
|
|
// Properties
|
|
CRITICAL_SECTION m_csLock;
|
|
BOOL m_fInitFailed;
|
|
#ifdef DBG
|
|
DWORD m_dwCsid;
|
|
CBuffer m_bfOwner;
|
|
CBuffer m_bfComment;
|
|
DWORD m_dwOwnerThread;
|
|
DWORD m_dwRecursion;
|
|
#endif
|
|
|
|
// Methods
|
|
};
|
|
|
|
|
|
//
|
|
//==============================================================================
|
|
//
|
|
// COwnCriticalSection
|
|
//
|
|
|
|
class COwnCriticalSection
|
|
{
|
|
public:
|
|
|
|
// Constructors & Destructor
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ DBGT("COwnCriticalSection::COwnCriticalSection")
|
|
COwnCriticalSection(
|
|
CCriticalSectionObject *pcs,
|
|
DEBUG_TEXT szSubroutine,
|
|
DEBUG_TEXT szComment)
|
|
{
|
|
m_pcsLock = pcs;
|
|
m_pcsLock->Enter(szSubroutine, szComment);
|
|
};
|
|
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ DBGT("COwnCriticalSection::~COwnCriticalSection")
|
|
~COwnCriticalSection()
|
|
{
|
|
m_pcsLock->Leave();
|
|
};
|
|
|
|
// Properties
|
|
// Methods
|
|
// Operators
|
|
|
|
protected:
|
|
// Properties
|
|
CCriticalSectionObject *m_pcsLock;
|
|
|
|
// Methods
|
|
};
|
|
|
|
#define LockSection(cx, reason) \
|
|
COwnCriticalSection csLock(cx, __SUBROUTINE__, reason)
|
|
|
|
#define LockSection2(cx, reason) \
|
|
COwnCriticalSection csLock2(cx, __SUBROUTINE__, reason)
|
|
|
|
#ifndef DBG
|
|
|
|
//
|
|
//In-line the simple Critical Section calls.
|
|
//
|
|
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ DBGT("CCriticalSectionObject::CCriticalSectionObject")
|
|
inline
|
|
CCriticalSectionObject::CCriticalSectionObject(
|
|
DWORD dwCsid)
|
|
{
|
|
m_fInitFailed = FALSE;
|
|
try {
|
|
// Preallocate the event used by the EnterCriticalSection
|
|
// function to prevent an exception from being thrown in
|
|
// CCriticalSectionObject::Enter
|
|
if (! InitializeCriticalSectionAndSpinCount(
|
|
&m_csLock, 0x80000000))
|
|
m_fInitFailed = TRUE;
|
|
}
|
|
catch (HRESULT hr) {
|
|
m_fInitFailed = TRUE;
|
|
}
|
|
}
|
|
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ DBGT("CCriticalSectionObject::~CCriticalSectionObject")
|
|
inline
|
|
CCriticalSectionObject::~CCriticalSectionObject()
|
|
{
|
|
if (m_fInitFailed)
|
|
return;
|
|
|
|
DeleteCriticalSection(&m_csLock);
|
|
}
|
|
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ DBGT("CCriticalSectionObject::Enter")
|
|
inline void
|
|
CCriticalSectionObject::Enter(
|
|
DEBUG_TEXT szOwner,
|
|
DEBUG_TEXT szComment)
|
|
{
|
|
if (m_fInitFailed)
|
|
throw (DWORD)SCARD_E_NO_MEMORY;
|
|
|
|
EnterCriticalSection(&m_csLock);
|
|
}
|
|
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ DBGT("CCriticalSectionObject::Leave")
|
|
inline void
|
|
CCriticalSectionObject::Leave(
|
|
void)
|
|
{
|
|
LeaveCriticalSection(&m_csLock);
|
|
}
|
|
|
|
#endif // !DBG
|
|
|
|
|
|
//
|
|
//==============================================================================
|
|
//
|
|
// CHandleObject
|
|
//
|
|
|
|
class CHandleObject
|
|
{
|
|
public:
|
|
|
|
// Constructors & Destructor
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ DBGT("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__ DBGT("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__ DBGT("CHandleObject::IsValid")
|
|
BOOL IsValid(void) const
|
|
{
|
|
return (NULL != m_hHandle) && (INVALID_HANDLE_VALUE != m_hHandle);
|
|
};
|
|
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ DBGT("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__ DBGT("CHandleObject::GetLastError")
|
|
DWORD GetLastError(void) const
|
|
{
|
|
return m_dwError;
|
|
};
|
|
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ DBGT("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__ DBGT("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__ DBGT("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__ DBGT("CHandleObject::operator HANDLE")
|
|
operator HANDLE(void) const
|
|
{
|
|
#ifdef _DEBUG
|
|
ASSERT(IsValid()); // Assert should be in callers
|
|
#endif
|
|
return Value();
|
|
};
|
|
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ DBGT("CHandleObject::operator=")
|
|
HANDLE operator=(HANDLE h)
|
|
{
|
|
return Open(h);
|
|
};
|
|
|
|
protected:
|
|
// Properties
|
|
HANDLE m_hHandle;
|
|
DWORD m_dwError;
|
|
#ifdef DBG
|
|
CBuffer m_bfName;
|
|
#endif
|
|
|
|
// Methods
|
|
};
|
|
|
|
#ifdef DBG
|
|
//
|
|
//==============================================================================
|
|
//
|
|
// CDynamicArray
|
|
//
|
|
|
|
template <class T>
|
|
class CDynamicValArray
|
|
{
|
|
public:
|
|
|
|
// Constructors & Destructor
|
|
|
|
CDynamicValArray(void)
|
|
{ m_Max = m_Mac = 0; m_pvList = NULL; };
|
|
|
|
virtual ~CDynamicValArray()
|
|
{ Clear(); };
|
|
|
|
|
|
// Properties
|
|
// Methods
|
|
|
|
void
|
|
Clear(void)
|
|
{
|
|
if (NULL != m_pvList)
|
|
{
|
|
delete[] m_pvList;
|
|
m_pvList = NULL;
|
|
m_Max = 0;
|
|
m_Mac = 0;
|
|
}
|
|
};
|
|
|
|
void
|
|
Empty(void)
|
|
{ m_Mac = 0; };
|
|
|
|
T
|
|
Set(
|
|
IN int nItem,
|
|
IN T pvItem);
|
|
|
|
T const
|
|
Get(
|
|
IN int nItem)
|
|
const;
|
|
|
|
DWORD
|
|
Count(void) const
|
|
{ return m_Mac; };
|
|
|
|
// Operators
|
|
T const
|
|
operator[](int nItem) const
|
|
{ return Get(nItem); };
|
|
|
|
|
|
protected:
|
|
// Properties
|
|
|
|
DWORD
|
|
m_Max, // Number of element slots available.
|
|
m_Mac; // Number of element slots used.
|
|
T *
|
|
m_pvList; // The elements.
|
|
|
|
|
|
// Methods
|
|
};
|
|
|
|
|
|
/*++
|
|
|
|
Set:
|
|
|
|
This routine sets an item in the collection array. If the array isn't that
|
|
big, it is expanded with NULL elements to become that big.
|
|
|
|
Arguments:
|
|
|
|
nItem - Supplies the index value to be set.
|
|
pvItem - Supplies the value to be set into the given index.
|
|
|
|
Return Value:
|
|
|
|
The value of the inserted value, or NULL on errors.
|
|
|
|
Author:
|
|
|
|
Doug Barlow (dbarlow) 7/13/1995
|
|
|
|
--*/
|
|
|
|
template<class T>
|
|
inline T
|
|
CDynamicValArray<T>::Set(
|
|
IN int nItem,
|
|
IN T pvItem)
|
|
{
|
|
DWORD index;
|
|
|
|
|
|
//
|
|
// Make sure the array is big enough.
|
|
//
|
|
|
|
if ((DWORD)nItem >= m_Max)
|
|
{
|
|
int newSize = (0 == m_Max ? 4 : m_Max);
|
|
while (nItem >= newSize)
|
|
newSize *= 2;
|
|
T *newList = new T[newSize];
|
|
if (NULL == newList)
|
|
throw (DWORD)ERROR_OUTOFMEMORY;
|
|
for (index = 0; index < m_Mac; index += 1)
|
|
newList[index] = m_pvList[index];
|
|
if (NULL != m_pvList)
|
|
delete[] m_pvList;
|
|
m_pvList = newList;
|
|
m_Max = newSize;
|
|
}
|
|
|
|
|
|
//
|
|
// Make sure intermediate elements are filled in.
|
|
//
|
|
|
|
if ((DWORD)nItem >= m_Mac)
|
|
{
|
|
for (index = m_Mac; index < (DWORD)nItem; index += 1)
|
|
m_pvList[index] = NULL;
|
|
m_Mac = (DWORD)nItem + 1;
|
|
}
|
|
|
|
|
|
//
|
|
// Fill in the list element.
|
|
//
|
|
|
|
m_pvList[(DWORD)nItem] = pvItem;
|
|
return pvItem;
|
|
}
|
|
|
|
/*++
|
|
|
|
Get:
|
|
|
|
This method returns the element at the given index. If there is no element
|
|
previously stored at that element, it returns NULL. It does not expand the
|
|
array.
|
|
|
|
Arguments:
|
|
|
|
nItem - Supplies the index into the list.
|
|
|
|
Return Value:
|
|
|
|
The value stored at that index in the list, or NULL if nothing has ever been
|
|
stored there.
|
|
|
|
Author:
|
|
|
|
Doug Barlow (dbarlow) 7/13/1995
|
|
|
|
--*/
|
|
|
|
template <class T>
|
|
inline T const
|
|
CDynamicValArray<T>::Get(
|
|
int nItem)
|
|
const
|
|
{
|
|
if (m_Mac <= (DWORD)nItem)
|
|
return 0;
|
|
else
|
|
return m_pvList[nItem];
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
//
|
|
//==============================================================================
|
|
//
|
|
// CAccessLock
|
|
//
|
|
|
|
class CAccessLock
|
|
{
|
|
public:
|
|
// Constructors & Destructor
|
|
|
|
CAccessLock(DWORD dwTimeout = CALAIS_LOCK_TIMEOUT);
|
|
~CAccessLock();
|
|
|
|
BOOL InitFailed(void) { return m_csLock.InitFailed(); }
|
|
|
|
#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
|
|
CDynamicValArray<DWORD> 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)
|
|
{
|
|
Unsignal(m_hSignalNoReaders);
|
|
};
|
|
void UnsignalNoWriters(void)
|
|
{
|
|
Unsignal(m_hSignalNoWriters);
|
|
};
|
|
|
|
friend class CLockRead;
|
|
friend class CLockWrite;
|
|
};
|
|
|
|
|
|
//
|
|
//==============================================================================
|
|
//
|
|
// CLockRead
|
|
//
|
|
|
|
class CLockRead
|
|
{
|
|
public:
|
|
|
|
// Constructors & Destructor
|
|
CLockRead(CAccessLock *pLock);
|
|
~CLockRead();
|
|
|
|
BOOL InitFailed(void) { return m_pLock->InitFailed(); }
|
|
|
|
// Properties
|
|
// Methods
|
|
// Operators
|
|
|
|
protected:
|
|
// Properties
|
|
CAccessLock * m_pLock;
|
|
|
|
// Methods
|
|
};
|
|
|
|
|
|
//
|
|
//==============================================================================
|
|
//
|
|
// CLockWrite
|
|
//
|
|
|
|
class CLockWrite
|
|
{
|
|
public:
|
|
|
|
// Constructors & Destructor
|
|
|
|
CLockWrite(CAccessLock *pLock);
|
|
~CLockWrite();
|
|
|
|
BOOL InitFailed(void) { return m_pLock->InitFailed(); }
|
|
|
|
// Properties
|
|
// Methods
|
|
// Operators
|
|
|
|
protected:
|
|
// Properties
|
|
|
|
CAccessLock *m_pLock;
|
|
|
|
|
|
// Methods
|
|
};
|
|
|
|
|
|
//
|
|
//==============================================================================
|
|
//
|
|
// CMutex
|
|
//
|
|
|
|
class CMutex
|
|
{
|
|
public:
|
|
|
|
// Constructors & Destructor
|
|
CMutex();
|
|
~CMutex();
|
|
|
|
// Properties
|
|
|
|
// Methods
|
|
void Grab(void);
|
|
BOOL Share(void);
|
|
void Invalidate(void);
|
|
void Take(void);
|
|
BOOL IsGrabbed(void);
|
|
BOOL IsGrabbedByMe(void);
|
|
BOOL IsGrabbedBy(DWORD dwThreadId);
|
|
BOOL InitFailed(void) { return m_csAccessLock.InitFailed(); }
|
|
|
|
// Operators
|
|
|
|
protected:
|
|
// Properties
|
|
CCriticalSectionObject m_csAccessLock;
|
|
DWORD m_dwOwnerThreadId;
|
|
DWORD m_dwGrabCount;
|
|
DWORD m_dwValidityCount;
|
|
CHandleObject m_hAvailableEvent;
|
|
|
|
// Methods
|
|
};
|
|
|
|
|
|
//
|
|
//==============================================================================
|
|
//
|
|
// CMultiEvent
|
|
//
|
|
|
|
class CMultiEvent
|
|
{
|
|
public:
|
|
|
|
// Constructors & Destructor
|
|
|
|
CMultiEvent();
|
|
~CMultiEvent();
|
|
|
|
|
|
// Properties
|
|
// Methods
|
|
HANDLE WaitHandle(void);
|
|
void Signal(void);
|
|
BOOL InitFailed(void) { return m_csLock.InitFailed(); }
|
|
|
|
// Operators
|
|
|
|
protected:
|
|
// Properties
|
|
CCriticalSectionObject m_csLock;
|
|
HANDLE m_rghEvents[4]; // Adjust this as necessary.
|
|
DWORD m_dwEventIndex;
|
|
|
|
// Methods
|
|
};
|
|
|
|
#endif // _LOCKS_H_
|
|
|