/*==================================================================================================
	CAGuard.h

	$Log: CAGuard.h,v $
	Revision 1.11  2004/08/26 08:13:33  jcm10
	finish bring up on Windows
	
	Revision 1.10  2003/12/17 21:00:16  dwyatt
	derive from CAMutex
	
	Revision 1.9  2003/12/17 19:49:15  dwyatt
	Windows conditionalizing
	
	Revision 1.8  2003/12/16 18:57:45  dwyatt
	Windows
	
	Revision 1.7  2003/11/22 00:07:10  dwyatt
	preliminary Win work
	
	Revision 1.6  2003/11/20 22:56:53  dwyatt
	__COREAUDIO_USE_FLAT_INCLUDES__
	
	Revision 1.5  2002/05/07 01:49:45  jcm10
	refromat the comment
	
	Revision 1.4  2002/04/18 02:20:12  jcm10
	clean up the header inclusion
	
	Revision 1.3  2002/04/09 07:57:25  bills
	fix try [jcm10]
	
	Revision 1.2  2002/04/02 20:42:07  bills
	add Try
	
	Revision 1.1  2002/03/01 01:52:40  jcm10
	moved here from ../Utility
	
	Revision 1.7  2001/07/17 20:13:37  jcm10
	fix the log line for neatness
	
	Revision 1.6  2001/07/04 02:00:26  jcm10
	give CAGuard a name for easier debugging
	
	Revision 1.5  2001/01/19 00:48:24  jcm10
	add more logging
	
	Revision 1.4  2001/01/08 23:51:04  jcm10
	remove #pragma once, since gcc claims it to be obsolete and issues an annoying warning to that effect when all warnings are enabled
	
	Revision 1.3  2000/09/13 02:07:29  jcm10
	use CoreAudioTypes.h instead of <CoreServices/CoreServices.h>
	
	Revision 1.2  2000/08/25 01:07:26  jcm10
	update things to build the XFiles and prune the CoreAudio target to just the code necessary to run it
	
	Revision 1.1  2000/08/24 23:36:32  jcm10
	first checked in
	
	Revision 0.0  2000/01/01 12:34:56  jcm10
	created
		
	$NoKeywords: $
==================================================================================================*/
#if !defined(__CAGuard_h__)
#define __CAGuard_h__

//==================================================================================================
//	Includes
//=============================================================================

//	Super Class Includes
#include "CAMutex.h"

#if CoreAudio_Debug
//	#define	Log_Average_Latency	1
#endif

//==================================================================================================
//	CAGuard
//
//	This is your typical mutex with signalling implemented via pthreads.
//	Lock() will return true if and only if the guard is locked on that call.
//	A thread that already has the guard will receive 'false' if it locks it
//	again. Use of the stack-based CAGuard::Locker class is highly recommended
//	to properly manage the recursive nesting. The Wait calls with timeouts
//	will return true if and only if the timeout period expired. They will
//	return false if they receive notification any other way.
//==================================================================================================

class	CAGuard : public CAMutex
{

//	Construction/Destruction
public:
					CAGuard(const char* inName);
	virtual			~CAGuard();

//	Actions
public:
	virtual void	Wait();
	virtual bool	WaitFor(UInt64 inNanos);
	virtual bool	WaitUntil(UInt64 inNanos);
	
	virtual void	Notify();
	virtual void	NotifyAll();

//	Implementation
protected:
#if TARGET_OS_MAC
	pthread_cond_t	mCondVar;
#else
	HANDLE			mEvent;
#endif
#if	Log_Average_Latency
	Float64			mAverageLatencyAccumulator;
	UInt32			mAverageLatencyCount;
#endif
	
//	Helper class to manage taking and releasing recursively
public:
	class			Locker
	{
	
	//	Construction/Destruction
	public:
					Locker(CAGuard& inGuard) : mGuard(inGuard), mNeedsRelease(false) { mNeedsRelease = mGuard.Lock(); }
					~Locker() { if(mNeedsRelease) { mGuard.Unlock(); } }
	
	private:
					Locker(const Locker&);
		Locker&		operator=(const Locker&);
	
	//	Actions
	public:
		void		Wait() { mGuard.Wait(); }
		bool		WaitFor(UInt64 inNanos) { return mGuard.WaitFor(inNanos); }
		bool		WaitUntil(UInt64 inNanos) { return mGuard.WaitUntil(inNanos); }
		
		void		Notify() { mGuard.Notify(); }
		void		NotifyAll() { mGuard.NotifyAll(); }

	//	Implementation
	private:
		CAGuard&	mGuard;
		bool		mNeedsRelease;	
	};

};

#endif
