464 lines
7.6 KiB
C++
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
|