#ifndef _xbODHEAPLOW_
#define _xbODHEAPLOW_
/*<<<***************************************************************************
The MIT License (MIT)

Copyright(C) 2013 - 2015 Marc Mirti Mancinelli, Christophe Lardau and Philippe Pamart (xdcube.org)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
////////////////////////////////////////////////////////////////////////////////
#Title: xbODheapLow
#Project: xdcBase
////////////////////////////////////////////////////////////////////////////////
#Author: Marc MIRTI MANCINELLI
#History:
<17/08/2013: creation.
12/02/2014: this notice inserted.
***************************************************************************>>>*/

#ifndef _xbBASE_
#	include "xbBase.h"
#endif

#include <intrin.h>

#ifdef _xbALLOCDEBUG
#	define DBGFILE_SZMAX 48
#endif

#pragma intrinsic(_ReadBarrier)
#pragma intrinsic(_WriteBarrier)
#pragma intrinsic(_ReadWriteBarrier)
/*
#define xbHEAPRELEASECHECK
#ifdef _DEBUG
#	define xbHEAPCOMPLETECHECK
#endif
*/

//#define xbSectShare_SLEEPTI(cSpin) (((cSpin)%2)?0:1) 
//#define xbSectShare_SLEEPTI(cSpin) (0) 
//#define xbSectShare_YIELD(cSpin) if (cSpin%2) ::YieldProcessor(); else ::Sleep(0); 
//#define xbSectShare_YIELD(cSpin) ::YieldProcessor();
#define xbSectShare_YIELD(cSpin) ::Sleep(0);

class xbEXPORT xbSectShareSimple
{
protected:
	volatile xbuint	m_thid;
public:
	xbSectShareSimple()
		:m_thid(0)
	{
#ifdef XDCBASE_X64
		xbRdbgAssert(sizeof(xbSectShareSimple)==8 && sizeof(m_thid)==8);
#else
		xbRdbgAssert(sizeof(xbSectShareSimple)==4 && sizeof(m_thid)==4);
#endif
	}
	~xbSectShareSimple()
	{
		xbRdbgAssert(!m_thid);
	}
	void Lock()
	{
		xbuint thid = ::xbThreadId();
#ifdef xbSectShare_DEBUG
		if (m_thid == thid)
			xbThrowElock(E_LASTERR,"Lock operation invalid, reentrance forbidden for this lock type",
			"xbSectShareSimple::Lock(): bad thid (m_thid:"+xbString(m_thid,true)+" != thid:"+xbString(thid,true)+")");
#endif
		int cLoop=0;
retryLock:
		while(m_thid)
		{
			xbSectShare_YIELD(++cLoop);
		}
#ifdef XDCBASE_X64
		if (xbInterlockCompareExchange64((int64*)&m_thid,thid,0) != 0)
#else
		if (xbInterlockCompareExchange32((long*)&m_thid,thid,0) != 0)
#endif
			goto retryLock;
/*
#ifdef xbSectShare_DEBUGLOOP
		int cLoop=0;
#endif
#ifdef XDCBASE_X64
		while (xbInterlockCompareExchange64((int64*)&m_thid,thid,0) != 0)
#else
		while (xbInterlockCompareExchange32((long*)&m_thid,thid,0) != 0)
#endif
		{
			::Sleep(0);
#ifdef xbSectShare_DEBUGLOOP
			cLoop++;
#endif
		}
#ifdef xbSectShare_DEBUGLOOP
		if (cLoop > 1)
		{
			char buf[256];
			_snprintf(buf,sizeof(buf),"[PB] xbSectShareSimple::Lock(): ok=true, cLoop=%d",cLoop);
			xbRelOutputLow(buf);
		}
#endif
*/

#ifdef xbSectShare_DEBUG
		if (m_thid != thid)
			xbThrowElock("Waiting for object operation failure, bad thread id",
				"xbSectShareSimple::Lock(): thid="+xbString(thid,true)+", m_thid="+xbString(m_thid,true));
#endif
	}
	void Unlock()
	{
		xbuint thid = ::xbThreadId();
#ifdef xbSectShare_DEBUG
		if (m_thid != thid)
			xbThrowElock(E_LASTERR,"Unlock operation invalid",
			"xbSectShareSimple::Unlock(): bad thid (m_thid: "+xbString(m_thid,true)+" != thid:"+xbString(thid,true)+")");
#endif
		m_thid = 0;
	}
private:
	xbDclNoCopyForObject(xbSectShareSimple);
};

class xbEXPORT xbSectShareSimpleRec
{
protected:
	volatile ulong	m_thid;
	ulong			m_cLock;
public:
	xbSectShareSimpleRec()
		:m_thid(0),m_cLock(0)
	{
		xbRdbgAssert(sizeof(xbSectShareSimpleRec)==8);
	}
	~xbSectShareSimpleRec()
	{
		xbRdbgAssert(!m_thid);
	}
	void Lock()
	{
		ulong thid = ::xbThreadId();
		if (m_thid == thid)
		{
			m_cLock++;
			return;
		}
		int cLoop=0;
retryLock:
		while(m_thid)
		{
			xbSectShare_YIELD(++cLoop);
		}
		if (xbInterlockCompareExchange32((long*)&m_thid,thid,0) != 0)
			goto retryLock;
/*
#ifdef xbSectShare_DEBUGLOOP
		int cLoop=0;
#endif
		while(xbInterlockCompareExchange32((long*)&m_thid,thid,0) != 0)
		{
			::Sleep(0);
#ifdef xbSectShare_DEBUGLOOP
			cLoop++;
#endif
		}
#ifdef xbSectShare_DEBUGLOOP
		if (cLoop > 1)
		{
			char buf[256];
			_snprintf(buf,sizeof(buf),"[PB] xbSectShareSimpleRec::Lock(): ok=true, cLoop=%d",cLoop);
			xbRelOutputLow(buf);
		}
#endif
*/
#ifdef xbSectShare_DEBUG
		if (m_thid != thid)
			xbThrowElock("Waiting for object operation failure, bad thread id",
				"xbSectShareSimpleRec::Lock(): thid="+xbString(thid,true)+", m_thid="+xbString(m_thid,true));
#endif
		m_cLock++;
	}
	void Unlock()
	{
		ulong thid = ::xbThreadId();
#ifdef xbSectShare_DEBUG
		if (m_thid != thid || !m_cLock)
			xbThrowElock(E_LASTERR,"Unlock operation invalid",
			"xbSectShareSimpleRec::Unlock(): bad thid (m_thid: "+xbString(m_thid,true)+" != thid:"+xbString(thid,true)+")");
#endif
		if (--m_cLock)
			return;
		m_thid = 0;
	}
private:
	xbDclNoCopyForObject(xbSectShareSimpleRec);
};

class xbEXPORT xbllSysHeap
{
public:
	xbllSysHeap(bool bMT,xbCtorMode CtorMode);
	virtual ~xbllSysHeap();
	void	Create();
	void	Destroy();

	void *Alloc(size_t cByte,xbOpMode opmode=xbOp_Required);
	void *ReAlloc(void *ptr,size_t cByte,xbOpMode opmode=xbOp_Required);
	void Free(void *ptr);
	bool Compact();

private:
	HANDLE	m_hHeap;
	bool	m_bMT;
//	int		m_cAlloc;

	xbDclNoNewForObject(xbllSysHeap);
	xbDclNoCopyForObject(xbllSysHeap);
};

class xbEXPORT xbllVirtualHeap
{
public:
	xbllVirtualHeap(bool bMT,xbCtorMode CtorMode);
	virtual ~xbllVirtualHeap();
	void	Create();
	void	Destroy();

	void *Alloc(size_t cByte,xbOpMode opmode=xbOp_Required);
	void *ReAlloc(void *ptr,size_t cByte,size_t cByteOld,xbOpMode opmode);
	void Free(void *ptr);
	bool Compact();
	ulong GetGranularity();
	bool Vlock(void *ptr,size_t cByte);
	bool Vunlock(void *ptr,size_t cByte);

protected:
	ulong	m_cByteGran;
private:
	
	xbDclNoNewForObject(xbllVirtualHeap);
	xbDclNoCopyForObject(xbllVirtualHeap);
};


#endif
