/*++

	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
