Leaked source code of windows server 2003
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

/*++
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_