/*
 *
 * @APPLE_LICENSE_HEADER_START@
 *
 * Copyright (c) 1999-2001 Apple Computer, Inc.  All Rights Reserved. The
 * contents of this file constitute Original Code as defined in and are
 * subject to the Apple Public Source License Version 1.2 (the 'License').
 * You may not use this file except in compliance with the License.  Please
 * obtain a copy of the License at http://www.apple.com/publicsource and
 * read it before using this file.
 *
 * This Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.  Please
 * see the License for the specific language governing rights and
 * limitations under the License.
 *
 *
 * @APPLE_LICENSE_HEADER_END@
 *
 */
/*
	File:		OSCond.h

	Contains:	A simple condition variable abstraction
	
	
		

*/

#ifndef _OSCOND_H_
#define _OSCOND_H_

#ifndef __Win32__
	#if __PTHREADS_MUTEXES__
		#include <pthread.h>
	#else
		#include "mycondition.h"
	#endif
#endif

#include "OSMutex.h"
#include "MyAssert.h"

class OSCond 
{
	public:

		OSCond();
		~OSCond();
		
		inline void 	Signal();
		inline void 	Wait(OSMutex* inMutex, SInt32 inTimeoutInMilSecs = 0);
		inline void		Broadcast();

	private:

#ifdef __Win32__
		HANDLE 				fCondition;
		UInt32				fWaitCount;
#elif __PTHREADS_MUTEXES__
		pthread_cond_t		fCondition;
		void				TimedWait(OSMutex* inMutex, SInt32 inTimeoutInMilSecs);
#else
		mycondition_t 		fCondition;
#endif
};

inline void OSCond::Wait(OSMutex* inMutex, SInt32 inTimeoutInMilSecs)
{ 
#ifdef __Win32__
	DWORD theTimeout = INFINITE;
	if (inTimeoutInMilSecs > 0)
		theTimeout = inTimeoutInMilSecs;
	inMutex->Unlock();
	fWaitCount++;
	DWORD theErr = ::WaitForSingleObject(fCondition, theTimeout);
	fWaitCount--;
	Assert((theErr == WAIT_OBJECT_0) || (theErr == WAIT_TIMEOUT));
	inMutex->Lock();
#elif __PTHREADS_MUTEXES__
	this->TimedWait(inMutex, inTimeoutInMilSecs);
#else
	Assert(fCondition != NULL);
	mycondition_wait(fCondition, inMutex->fMutex, inTimeoutInMilSecs);
#endif
}

inline void OSCond::Signal()
{
#ifdef __Win32__
	BOOL theErr = ::SetEvent(fCondition);
	Assert(theErr == TRUE);
#elif __PTHREADS_MUTEXES__
	pthread_cond_signal(&fCondition);
#else
	Assert(fCondition != NULL);
	mycondition_signal(fCondition);
#endif
}

inline void OSCond::Broadcast()
{
#ifdef __Win32__
	//
	// There doesn't seem like any more elegant way to
	// implement Broadcast using events in Win32.
	// This will work, it may generate spurious wakeups,
	// but condition variables are allowed to generate
	// spurious wakeups
	UInt32 waitCount = fWaitCount;
	for (UInt32 x = 0; x < waitCount; x++)
	{
		BOOL theErr = ::SetEvent(fCondition);
		Assert(theErr == TRUE);
	}
#elif __PTHREADS_MUTEXES__
	pthread_cond_broadcast(&fCondition);
#else
	Assert(fCondition != NULL);
	mycondition_broadcast(fCondition);
#endif
}

#endif //_OSCOND_H_
