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


		MCSMPSharedCriticalSection.h

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

		Author:	Pierre-Sylvain Desse
		Date:	7/01/09


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

#ifndef __MCSMPSharedCriticalSection__
#define __MCSMPSharedCriticalSection__

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


class TMCSharedCriticalSection;


#ifdef qSMP

class TMCSharedCriticalSectionInternal;

class TMCSharedCriticalSection : public TMCObject
{
public:
	TMCSharedCriticalSection();
	~TMCSharedCriticalSection();

	void	EnterShared();
	void	LeaveShared();

	void	EnterExclusive();
	void	LeaveExclusive();

protected:
	TMCSharedCriticalSectionInternal*	fInternal;

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


class TMCSharedCriticalSectionArrayInternal;

class TMCSharedCriticalSectionArray : public TMCObject
{
public:
	TMCSharedCriticalSectionArray();
	~TMCSharedCriticalSectionArray();

	void	Initialize(int32 num);

	void	EnterShared(int32 index);
	void	LeaveShared(int32 index);

	void	EnterExclusive(int32 index);
	void	LeaveExclusive(int32 index);

protected:
	TMCSharedCriticalSectionArrayInternal*	fInternal;

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

#else // if qSMP

#error "You must define qSMP !!!"


#endif


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

/// \addtogroup MCCore
/// \{

// ****************************************************************************
//							CWhileInSharedCS	
// 
/// 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
/// in shared access mode.
/// For more information on critical region see TMCSharedCriticalSection.
///
/// <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
/// {
///   CWhileInSharedCS cs(criticalSection);
///
///   // Code excuted inside the critical section
///   ...
/// }
/// // Code excuted outside the critical section
/// ...
/// \endcode
///
class CWhileInSharedCS : public TMCObject
{
public:
	CWhileInSharedCS(TMCSharedCriticalSection& theCS) { fCS=&theCS; if (fCS) fCS->EnterShared(); }
	~CWhileInSharedCS() {Clean();}
	void Clean() {if (fCS) {fCS->LeaveShared();} fCS = nil;}

protected:
	TMCSharedCriticalSection* fCS;
	
	friend class CWhileInSharedExclusiveCS;
};

// ****************************************************************************
//							CWhileInSharedExclusiveCS	
// 
/// 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
/// will be promoted from shared to exclusive access mode.
class CWhileInSharedExclusiveCS : public TMCObject
{
public:
	CWhileInSharedExclusiveCS(CWhileInSharedCS& theCS) : fCS(theCS)
	{
		fCS.fCS->LeaveShared();
		fCS.fCS->EnterExclusive();
	}

	~CWhileInSharedExclusiveCS()
	{
		fCS.fCS->EnterShared();
		fCS.fCS->LeaveExclusive();
	}

protected:
	CWhileInSharedCS& fCS;
};

// ****************************************************************************
//							CWhileInExclusiveCS	
// 
/// 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
/// in exclusive access mode.
/// For more information on critical region see TMCSharedCriticalSection.
///
/// <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
/// {
///   CWhileInExclusiveCS cs(criticalSection);
///
///   // Code excuted inside the critical section
///   ...
/// }
/// // Code excuted outside the critical section
/// ...
/// \endcode
///
class CWhileInExclusiveCS : public TMCObject
{
	public:
		CWhileInExclusiveCS(TMCSharedCriticalSection& theCS) { fCS=&theCS; if (fCS) fCS->EnterExclusive(); }
		~CWhileInExclusiveCS() {Clean();}
		void Clean() {if (fCS) {fCS->LeaveExclusive();} fCS = nil;}

	protected:
		TMCSharedCriticalSection * fCS;
};

class CWhileInExclusiveCSArray : public TMCObject
{
	public:
		CWhileInExclusiveCSArray(TMCSharedCriticalSectionArray& theCS, int32 index) { fCS=&theCS; fIndex=index; if (fCS) fCS->EnterExclusive(fIndex); }
		~CWhileInExclusiveCSArray() {Clean();}
		void Clean() {if (fCS) {fCS->LeaveExclusive(fIndex);} fCS = nil;}

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



#endif

