#ifndef __READERWRITER_CPP
#define __READERWRITER_CPP

/*++

Copyright (C) 1996-2001 Microsoft Corporation

Module Name:

	ReaderWriter.cpp

Abstract:

	Enhancements to current functionality: 

		Timeout mechanism should track across waits.
		AddRef/Release on task when scheduling.
		Enhancement Ticker logic.

History:

--*/

#include <windows.h>
#include <ReaderWriter.h>

/******************************************************************************
 *
 *	Name:
 *
 *	
 *  Description:
 *
 *	
 *****************************************************************************/

WmiMultiReaderSingleWriter :: WmiMultiReaderSingleWriter ( 

	const LONG &a_ReaderSize 

) : m_ReaderSize ( a_ReaderSize ) ,
	m_ReaderSemaphore ( NULL ) ,
	m_InitializationStatusCode ( e_StatusCode_Success ) ,
	m_WriterCriticalSection (NOTHROW_LOCK)
{
	m_InitializationStatusCode = WmiHelper :: InitializeCriticalSection ( & m_WriterCriticalSection ) ;
	if ( m_InitializationStatusCode == e_StatusCode_Success ) 
	{
		m_ReaderSemaphore = CreateSemaphore ( NULL , m_ReaderSize , m_ReaderSize , NULL ) ;
		if ( ! m_ReaderSemaphore )
		{
			m_InitializationStatusCode = e_StatusCode_OutOfResources ;
		}
	}
}

/******************************************************************************
 *
 *	Name:
 *
 *	
 *  Description:
 *
 *	
 *****************************************************************************/

WmiMultiReaderSingleWriter :: ~WmiMultiReaderSingleWriter ()
{
	WmiHelper :: DeleteCriticalSection ( & m_WriterCriticalSection ) ;

	if ( m_ReaderSemaphore )
	{
		CloseHandle ( m_ReaderSemaphore ) ;
	}
}

/******************************************************************************
 *
 *	Name:
 *
 *	
 *  Description:
 *
 *	
 *****************************************************************************/

WmiStatusCode WmiMultiReaderSingleWriter :: Initialize ()
{
	return m_InitializationStatusCode ;
}

/******************************************************************************
 *
 *	Name:
 *
 *	
 *  Description:
 *
 *	
 *****************************************************************************/

WmiStatusCode WmiMultiReaderSingleWriter :: UnInitialize ()
{
	WmiStatusCode t_StatusCode = e_StatusCode_Success ;

	return t_StatusCode ;
}

/******************************************************************************
 *
 *	Name:
 *
 *	
 *  Description:
 *
 *	
 *****************************************************************************/

WmiStatusCode WmiMultiReaderSingleWriter :: EnterRead ()
{
	if ( m_InitializationStatusCode == e_StatusCode_Success ) 
	{
		WmiStatusCode t_StatusCode = WmiHelper :: EnterCriticalSection ( & m_WriterCriticalSection ) ;
		if ( t_StatusCode == e_StatusCode_Success )
		{
			LONG t_Reason = WaitForSingleObject ( m_ReaderSemaphore , INFINITE ) ;
			if ( t_Reason != WAIT_OBJECT_0 )
			{
				t_StatusCode = e_StatusCode_Unknown ;
			}

			WmiHelper :: LeaveCriticalSection ( & m_WriterCriticalSection ) ;
		}

		return t_StatusCode ;
	}

	return e_StatusCode_NotInitialized ;
}

/******************************************************************************
 *
 *	Name:
 *
 *	
 *  Description:
 *
 *	
 *****************************************************************************/

WmiStatusCode WmiMultiReaderSingleWriter :: EnterWrite ()
{
	if ( m_InitializationStatusCode == e_StatusCode_Success ) 
	{
		WmiStatusCode t_StatusCode = WmiHelper :: EnterCriticalSection ( & m_WriterCriticalSection ) ;
		if ( t_StatusCode == e_StatusCode_Success )
		{
			bool t_Waiting = true ;

			while ( t_Waiting )
			{
				LONG t_Reason = WaitForSingleObject ( m_ReaderSemaphore , INFINITE ) ;
				if ( t_Reason != WAIT_OBJECT_0 )
				{
					WmiHelper :: LeaveCriticalSection ( & m_WriterCriticalSection ) ;
					return e_StatusCode_Unknown ;
				}

				LONG t_SemaphoreCount = 0 ;
				BOOL t_Status = ReleaseSemaphore ( m_ReaderSemaphore , 1 , & t_SemaphoreCount ) ;
				if ( t_Status )
				{
					if ( t_SemaphoreCount == m_ReaderSize - 1 )
					{
						t_Waiting = false ;
					}
					else
					{
						SwitchToThread () ; 
					}
				}
				else
				{
					WmiHelper :: LeaveCriticalSection ( & m_WriterCriticalSection ) ;
					return e_StatusCode_Unknown ;
				}
			}

			return t_StatusCode ;
		}
	}

	return e_StatusCode_NotInitialized ;
}

/******************************************************************************
 *
 *	Name:
 *
 *	
 *  Description:
 *
 *	
 *****************************************************************************/

WmiStatusCode WmiMultiReaderSingleWriter :: LeaveRead ()
{
	LONG t_SemaphoreCount = 0 ;
	BOOL t_Status = ReleaseSemaphore ( m_ReaderSemaphore , 1 , & t_SemaphoreCount ) ;
	if ( t_Status )
	{
		return e_StatusCode_Success ;
	}

	return e_StatusCode_Unknown ;
}

/******************************************************************************
 *
 *	Name:
 *
 *	
 *  Description:
 *
 *	
 *****************************************************************************/

WmiStatusCode WmiMultiReaderSingleWriter :: LeaveWrite ()
{
	return WmiHelper :: LeaveCriticalSection ( & m_WriterCriticalSection ) ;
}

/******************************************************************************
 *
 *	Name:
 *
 *	
 *  Description:
 *
 *	
 *****************************************************************************/

WmiMultiReaderMultiWriter :: WmiMultiReaderMultiWriter ( 

	const LONG &a_ReaderSize ,
	const LONG &a_WriterSize 

) : m_ReaderSize ( a_ReaderSize ) ,
	m_ReaderSemaphore ( NULL ) ,
	m_WriterSize ( a_WriterSize ) ,
	m_WriterSemaphore ( NULL ) ,
	m_InitializationStatusCode ( e_StatusCode_Success ) 
{
	if ( m_InitializationStatusCode == e_StatusCode_Success ) 
	{
		m_ReaderSemaphore = CreateSemaphore ( NULL , m_ReaderSize , m_ReaderSize , NULL ) ;
		if ( ! m_ReaderSemaphore )
		{
			m_InitializationStatusCode = e_StatusCode_OutOfResources ;
		}
	}

	if ( m_InitializationStatusCode == e_StatusCode_Success ) 
	{
		m_WriterSemaphore = CreateSemaphore ( NULL , m_WriterSize , m_WriterSize , NULL ) ;
		if ( ! m_ReaderSemaphore )
		{
			m_InitializationStatusCode = e_StatusCode_OutOfResources ;
		}
	}
}

/******************************************************************************
 *
 *	Name:
 *
 *	
 *  Description:
 *
 *	
 *****************************************************************************/

WmiMultiReaderMultiWriter :: ~WmiMultiReaderMultiWriter ()
{
	if ( m_ReaderSemaphore )
	{
		CloseHandle ( m_ReaderSemaphore ) ;
	}

	if ( m_WriterSemaphore )
	{
		CloseHandle ( m_WriterSemaphore ) ;
	}
}

/******************************************************************************
 *
 *	Name:
 *
 *	
 *  Description:
 *
 *	
 *****************************************************************************/

WmiStatusCode WmiMultiReaderMultiWriter :: Initialize ()
{
	return m_InitializationStatusCode ;
}

/******************************************************************************
 *
 *	Name:
 *
 *	
 *  Description:
 *
 *	
 *****************************************************************************/

WmiStatusCode WmiMultiReaderMultiWriter :: UnInitialize ()
{
	WmiStatusCode t_StatusCode = e_StatusCode_Success ;

	return t_StatusCode ;
}

/******************************************************************************
 *
 *	Name:
 *
 *	
 *  Description:
 *
 *	
 *****************************************************************************/

WmiStatusCode WmiMultiReaderMultiWriter :: EnterRead ( const LONG &a_Timeout )
{
	if ( m_InitializationStatusCode == e_StatusCode_Success ) 
	{
		WmiStatusCode t_StatusCode = e_StatusCode_Success ;

		LONG t_Reason = WaitForSingleObject ( m_WriterSemaphore , INFINITE ) ;
		if ( t_Reason != WAIT_OBJECT_0 )
		{
			return e_StatusCode_Unknown ;
		}

		t_Reason = WaitForSingleObject ( m_ReaderSemaphore , INFINITE ) ;
		if ( t_Reason != WAIT_OBJECT_0 )
		{
			t_StatusCode = e_StatusCode_Unknown ;
		}

		LONG t_SemaphoreCount = 0 ;
		BOOL t_Status = ReleaseSemaphore ( m_WriterSemaphore , 1 , & t_SemaphoreCount ) ;
		if ( ! t_Status )
		{
			t_StatusCode = e_StatusCode_Unknown ;
		}

		return t_StatusCode ;
	}

	return e_StatusCode_NotInitialized ;
}

/******************************************************************************
 *
 *	Name:
 *
 *	
 *  Description:
 *
 *	
 *****************************************************************************/

WmiStatusCode WmiMultiReaderMultiWriter :: EnterWrite ( const LONG &a_Timeout )
{
	if ( m_InitializationStatusCode == e_StatusCode_Success ) 
	{
		WmiStatusCode t_StatusCode = e_StatusCode_Success ; 

		LONG t_Reason = WaitForSingleObject ( m_WriterSemaphore , INFINITE ) ;
		if ( t_Reason != WAIT_OBJECT_0 )
		{
			return e_StatusCode_Unknown ;
		}

		bool t_Waiting = true ;

		while ( t_Waiting )
		{
			LONG t_Reason = WaitForSingleObject ( m_ReaderSemaphore , INFINITE ) ;
			if ( t_Reason != WAIT_OBJECT_0 )
			{
				LONG t_SemaphoreCount = 0 ;
				BOOL t_Status = ReleaseSemaphore ( m_WriterSemaphore , 1 , & t_SemaphoreCount ) ;
				if ( ! t_Status )
				{
					t_StatusCode = e_StatusCode_Unknown ;
				}

				return e_StatusCode_Unknown ;
			}

			LONG t_SemaphoreCount = 0 ;
			BOOL t_Status = ReleaseSemaphore ( m_ReaderSemaphore , 1 , & t_SemaphoreCount ) ;
			if ( t_Status )
			{
				if ( t_SemaphoreCount == m_ReaderSize - 1 )
				{
					t_Waiting = false ;
				}
				else
				{
					SwitchToThread () ;
				}
			}
			else
			{
				LONG t_SemaphoreCount = 0 ;
				BOOL t_Status = ReleaseSemaphore ( m_WriterSemaphore , 1 , & t_SemaphoreCount ) ;
				if ( ! t_Status )
				{
					t_StatusCode = e_StatusCode_Unknown ;
				}

				return e_StatusCode_Unknown ;
			}
		}

		return t_StatusCode ;
	}

	return e_StatusCode_NotInitialized ;
}

/******************************************************************************
 *
 *	Name:
 *
 *	
 *  Description:
 *
 *	
 *****************************************************************************/

WmiStatusCode WmiMultiReaderMultiWriter :: LeaveRead ()
{
	LONG t_SemaphoreCount = 0 ;
	BOOL t_Status = ReleaseSemaphore ( m_ReaderSemaphore , 1 , & t_SemaphoreCount ) ;
	if ( t_Status )
	{
		return e_StatusCode_Success ;
	}

	return e_StatusCode_Unknown ;
}

/******************************************************************************
 *
 *	Name:
 *
 *	
 *  Description:
 *
 *	
 *****************************************************************************/

WmiStatusCode WmiMultiReaderMultiWriter :: LeaveWrite ()
{
	LONG t_SemaphoreCount = 0 ;
	BOOL t_Status = ReleaseSemaphore ( m_WriterSemaphore , 1 , & t_SemaphoreCount ) ;
	if ( t_Status )
	{
		return e_StatusCode_Success ;
	}

	return e_StatusCode_Unknown ;
}

#endif __READERWRITER_CPP