windows-nt/Source/XPSP1/NT/inetsrv/iis/staxinc/export/rwintrnl.h
2020-09-26 16:20:57 +08:00

464 lines
7.6 KiB
C++

/*++
rwintrnl.h
Reader/Writer locks internal header file
This file defines several objects used to implement
reader/writer locks, however these objects should
not be directly used by any client of rw.h
--*/
#ifndef _RWINTRNL_H_
#define _RWINTRNL_H_
class CHandleInfo {
/*++
This class keeps track of all the handles we've allocated for
use by various threads. We can't use Thread Local Storage
directly because we can be dynamically unloaded, in which case
we need to free all of our HANDLES !
--*/
private :
//
// Signature for our
//
DWORD m_dwSignature ;
class CHandleInfo* m_pNext ;
class CHandleInfo* m_pPrev ;
CHandleInfo( CHandleInfo& ) ;
CHandleInfo& operator=( CHandleInfo& ) ;
//
// Global lock to protect free and allocated lists !
//
static CRITICAL_SECTION s_InUseList ;
//
// Allocated CHandleInfo objects !
//
static CHandleInfo s_Head ;
//
// Free CHandleInfo objects
//
static CHandleInfo s_FreeHead ;
//
// Number of Free CHandleInfo objects in the s_FreeHead list
//
static DWORD s_cFreeList ;
enum constants {
//
// Maximum number of CHandleInfo objects we'll hold onto !
//
MAX_FREE = 64,
//
// Initial number of CHandleInfo objects we'll allocate !
//
INITIAL_FREE = 32,
//
// Signature in our objects !
//
SIGNATURE = (DWORD)'hnwR'
} ;
//
// Memory Allocation is done the hard way !
//
void* operator new( size_t size ) ;
void operator delete( void *pv ) ;
//
// List Manipulation routines !
//
void
InsertAtHead( CHandleInfo* pHead ) ;
//
// Remove the element from the list - returns this pointer !
//
CHandleInfo*
RemoveList( ) ;
public :
//
// Constructor and Destructor !
//
CHandleInfo() ;
~CHandleInfo() ;
//
// This is public for all to use !
//
HANDLE m_hSemaphore ;
//
// This is an auto-reset event handle available for anybody
// and retrievable through GetPerThreadEvent() ;
//
HANDLE m_hEvent ;
//
// Initialize the class
//
static BOOL
InitClass() ;
//
// Terminate the class - release all outstanding handles !
//
static void
TermClass() ;
//
// Get a CHandleInfo object !
//
static CHandleInfo*
AllocHandleInfo() ;
//
// release a CHandleInfo object !
//
static void
ReleaseHandleInfo( CHandleInfo* ) ;
//
// Check that the object is valid !
//
BOOL
IsValid() {
return m_dwSignature == SIGNATURE &&
m_pNext != 0 &&
m_pPrev != 0 ;
}
} ;
//
// This class serves two purposes : to provide for a linkable object
// on which we can queue threads blocked upon semaphore handles, and
// a mechanism to get and set semaphore handles for reader/writer locks etc...
//
class CWaitingThread : public CQElement {
private :
enum {
POOL_HANDLES = 64,
} ;
//
// Semaphore that we can use to block the thread !
//
CHandleInfo *m_pInfo ;
//
// Var to hold error that may have occurred manipulating the lock !
//
DWORD m_dwError ;
//
// Thread Local Storage offset for holding the handles !
//
static DWORD g_dwThreadHandle ;
//
// Array of Handles to Semaphores which we stash away in case
// we have to release the handle being used by a thread at some point !
//
static HANDLE g_rghHandlePool[ POOL_HANDLES ] ;
//
// No copying of these objects allowed !!!
//
CWaitingThread( CWaitingThread& ) ;
CWaitingThread& operator=( CWaitingThread& ) ;
public :
#ifdef DEBUG
//
// Thread Id - handy for debuggiing
//
DWORD m_dwThreadId ;
#endif
CWaitingThread() ;
//
// Functions to be called from the DllEntryProc function !
//
static BOOL
InitClass() ;
static BOOL
TermClass() ;
//
// Thread Entry/Exit routines which can allocate semaphore handles for us !
//
static void
ThreadEnter() ;
static void
ThreadExit() ;
//
// Function which gives us our Event Handle
//
inline HANDLE
GetThreadEvent() const ;
//
// Function which gives us our thread handle !
//
inline HANDLE
GetThreadHandle() const ;
//
// Function which will release a HANDLE to the Pool of available
// semaphore handles !
//
inline void
PoolHandle(
HANDLE h
) const ;
//
// Function which will remove a handle from our thread's TLS !
// The argument must originally be from the calling thread's TLS
//
inline void
ClearHandle(
HANDLE h
) ;
//
// Function which blocks the calling thread !!
//
inline BOOL
Wait() const ;
//
// Function which can release a thread !!
//
inline BOOL
Release() const ;
//
// This function is used in debug builds to check the state of our semaphore handles !
//
static inline
BOOL ValidateHandle(
HANDLE h
) ;
} ;
typedef TLockQueue< CWaitingThread > TThreadQueue ;
class CSingleReleaseQueue {
private :
//
// Queue of threads waiting to own the lock !
//
TThreadQueue m_Waiting ;
public :
#ifdef DEBUG
DWORD m_ThreadIdNext ;
#endif
CSingleReleaseQueue(
BOOL IsSignalled = TRUE
) ;
//
// Release a single waiting thread !
//
void Release( ) ;
//
// Wait for the queue to become signalled !
//
void WaitForIt(
CWaitingThread& myself
) ;
//
// Wait for the queue to become signalled
//
void WaitForIt( ) ;
} ;
//
// This class is similar to a semaphore -
// Threads block indefinately on WaitForIt() and another
// thread may release as many threads as required by calling
// Release().
//
class CEventQueue {
private :
//
// Number of threads that should be allowed to pass
// through the event !!!
//
long m_ReleaseCount ;
//
// Queue of threads blocked on this event !
//
TThreadQueue m_WaitingThreads ;
//
// Any thread may call this to release threads from the queue
//
BOOL ResumeThreads(
CWaitingThread*
) ;
public :
//
// Create an event queue object
//
CEventQueue(
long cInitial = 0
) ;
~CEventQueue() ;
void Release(
long NumberToRelease
) ;
void WaitForIt(
CWaitingThread& myself
) ;
void WaitForIt() ;
void Reset() ;
} ;
//
// Function which gives us our thread handle !
//
inline HANDLE
CWaitingThread::GetThreadHandle() const {
_ASSERT( ValidateHandle( m_pInfo->m_hSemaphore ) ) ;
return m_pInfo->m_hSemaphore ;
}
//
// Function which takes a handle (must not be ours)
// and places it into a pool of handles available for other threads !
//
inline void
CWaitingThread::PoolHandle( HANDLE h ) const {
_ASSERT( h != m_pInfo->m_hSemaphore && h != 0 ) ;
_ASSERT( ValidateHandle( h ) ) ;
for( int i=0;
i < sizeof( g_rghHandlePool ) / sizeof( g_rghHandlePool[0] ) &&
h != 0;
i++ ) {
h = (HANDLE)InterlockedExchangePointer( (PVOID*)&g_rghHandlePool[i], h ) ;
}
if( h != 0 ) {
_VERIFY( CloseHandle( h ) ) ;
}
}
//
// Release our Handle from TLS, somebody else is going to use it !
//
inline void
CWaitingThread::ClearHandle( HANDLE h ) {
_ASSERT( h != 0 && h == m_pInfo->m_hSemaphore ) ;
m_pInfo->m_hSemaphore = 0 ;
//TlsSetValue( g_dwThreadHandle, (LPVOID) 0 ) ;
}
//
// Block on the handle held within our object !
//
inline BOOL
CWaitingThread::Wait() const {
_ASSERT( m_pInfo->m_hSemaphore != 0 ) ;
return WAIT_OBJECT_0 == WaitForSingleObject( m_pInfo->m_hSemaphore, INFINITE ) ;
}
//
// Release a thread which is blocked on the semaphore within !!
//
inline BOOL
CWaitingThread::Release() const {
_ASSERT( m_pInfo->m_hSemaphore != 0 ) ;
_ASSERT( ValidateHandle( m_pInfo->m_hSemaphore ) ) ;
return ReleaseSemaphore( m_pInfo->m_hSemaphore, 1, NULL ) ;
}
//
//
//
inline BOOL
CWaitingThread::ValidateHandle( HANDLE h ) {
DWORD dw = WaitForSingleObject( h, 0 ) ;
_ASSERT( dw == WAIT_TIMEOUT ) ;
return dw == WAIT_TIMEOUT ;
}
inline HANDLE
CWaitingThread::GetThreadEvent() const {
return m_pInfo->m_hEvent ;
}
#endif