/****************************************************************************************


		MCSMPCriticalSection.h

		Copyright: (c) 2001 Eovia Corp. All rights reserved.

		Author:	Emil
		Date:	3/27/98

		Revision History

		when		who			what & why
		==========	==========	======================================================
		10/18/99	Yann		SetAtomicCounterValue was returning an int32 on the Mac
		7/29/99		Eml			Atomic Counter fix
		6/10/99		Ian			Array API changes.
		04/23/99	Eml/scooper	stub MakeSMPProcess
		4/22/99		Eml			Reverted to old TLS mechanism. New one could not work on the Mac
		5/27/98		Eml			include MCOSConfig.h

*****************************************************************************************/

#ifndef __MCSMPCriticalSection__
#define __MCSMPCriticalSection__

#include "MCBasicDefines.h"
#include "MCBasicTypes.h"
#include "MCOSConfig.h"
#include "MCCompiler.h"


class TMCCriticalSection;


#ifdef qSMP


TMCCriticalSection * NewCS();
void DeleteCS(TMCCriticalSection * aCS);
void EnterCS(TMCCriticalSection * aCS);
void LeaveCS(TMCCriticalSection * aCS);


struct TMCCriticalSectionArrayInternal;

class TMCCriticalSectionArray
{
public:
	TMCCriticalSectionArray();
	~TMCCriticalSectionArray();

	void	Initialize(int32 num);
	void	CleanUp();

	void	Enter(int32 index);
	void	Leave(int32 index);

protected:
	TMCCriticalSectionArrayInternal*	fInternal;

private:
	TMCCriticalSectionArray(const TMCCriticalSectionArray&);
	TMCCriticalSectionArray& operator = (const TMCCriticalSectionArray&);
};

#else // if qSMP

#error "You must define qSMP !!!"

/*
//Stubbed definitions of SMP calls when qSMP is not defined

//typedef int32 TMCCriticalSection;

#define NewCS() nil
#define DeleteCS(x)
#define EnterCS(x)
#define LeaveCS(x)

*/
#endif


//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//
// General Tools useful with SMP
//
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

/// \addtogroup MCCore
/// \{

// ****************************************************************************
//							CWhileInCS	
// 
/// This class should be used to declare a local variable. The life span of this
/// variable determines what block of code is encapsulated in the critical section.
/// For more information on critical region see TMCCriticalSection.
///
/// <P>One of the advantage of using a local variable is that the destructor is
/// called if an exception is thrown or if return is called in the middle of the
/// function</P>
///
/// <P>For instance, you could write:</P>
///
/// \code
/// {
///   CWhileInCS cs(criticalSection);
///
///   // Code excuted inside the critical section
///   ...
/// }
/// // Code excuted outside the critical section
/// ...
/// \endcode
///
class CWhileInCS : public TMCObject
{
	public:
		CWhileInCS(TMCCriticalSection * theCS) { fCS=theCS; if (fCS) EnterCS(fCS); }
		~CWhileInCS() {Clean();}
		void Clean() {if (fCS) {LeaveCS(fCS);} fCS = nil;}

	protected:
		TMCCriticalSection * fCS;
};
/// \}


// ****************************************************************************
//							CWhileInConditionalCS	
//
/// Use CWhileInCS instead.
///
class CWhileInConditionalCS : public TMCObject
{
	public:
		CWhileInConditionalCS(TMCCriticalSection * theCS) : fCS(theCS),fLocked(false) {}
		~CWhileInConditionalCS() { 	Clean(); }
		boolean Cond(boolean *cond) {EnterCS(fCS); fLocked = true; return *cond;}
		boolean Cond(void **cond) {EnterCS(fCS); fLocked = true; return (*cond) != nil;}
		void Clean() {if (fLocked) {LeaveCS(fCS);} fLocked = false;}

	protected:
		TMCCriticalSection * fCS;
		boolean fLocked;
};


// ****************************************************************************
//							CWhileInCSArray	
// 
class CWhileInCSArray
{
	public:
		CWhileInCSArray(TMCCriticalSectionArray& theCS, int32 index) { fCS=&theCS; fIndex=index; if (fCS) fCS->Enter(fIndex); }
		~CWhileInCSArray() { Clean(); }
		void Clean() {if (fCS) { fCS->Leave(fIndex); } fCS = nil;}

	protected:
		TMCCriticalSectionArray*	fCS;
		int32						fIndex;
};
/// \}


#endif

