#ifndef _xbLOCK_
#define _xbLOCK_
/*<<<***************************************************************************
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: xbLock
#Project: xdcBase
////////////////////////////////////////////////////////////////////////////////
#Author: Marc MIRTI MANCINELLI
#History:
<15/09/2013: creation.
12/02/2014: this notice inserted.
***************************************************************************>>>*/

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#ifndef _xbHEAP_
#	include "xbHeap.h"
#endif

#ifndef _xbSYNC_
#	include "xbSync.h"
#endif

//deadlock detection
#ifdef _RELDBG
#	define xbSectShareSTD_DEADLOCKPREVENT		//Detection of possible deadlock cases before they happen
//#	define xbSectShareRW_DEADLOCKPREVENT		//Detection of possible deadlock cases before they happen
//#	define xbSectShareSTD_DEADLOCKDETECT		//Detection when deadlock happens
#	define xbSectShareRW_DEADLOCKDETECT			//Detection when deadlock happens
#else
#	define xbSectShareSTD_DEADLOCKDETECT		//Detection when deadlock happens
#	define xbSectShareRW_DEADLOCKDETECT		//Detection when deadlock happens
#endif

#ifdef _RELDBG
#	define xbSectShare_DEBUG
#	define xbSectShare_DEBUGLOOP
#endif

#define xbSectShareSTD_STAT
#define xbSectShareRW_STAT

#if defined(xbSectShareSTD_DEADLOCKPREVENT) && !defined(xbSectShareSTD_DEADLOCKDETECT)
#	define xbSectShareSTD_DEADLOCKDETECT
#endif

#if defined(xbSectShareRW_DEADLOCKPREVENT) && !defined(xbSectShareRW_DEADLOCKDETECT)
#	define xbSectShareRW_DEADLOCKDETECT
#endif

#if defined(xbSectShareSTD_DEADLOCKPREVENT) || defined(xbSectShareRW_DEADLOCKPREVENT)
#	define xbSectShareBase_DEADLOCKPREVENT
#endif

#define xbStackShare_SIZEMAX		48
#define xbStackShare_CHECKTIMEMAX	2000
#define xbStackShare_WAITTIMEMAX	60000

#define xbSectShareSpin_SPINCOUNT	2
#define xbSectShareSpin_TIMEOUT		(60*5*1000)

//#define xbSectShareSpinRW_READTHID	0xFFFFFFFF

class xbEXPORT xbSectShareBase;

enum xbLockMode
{
	xbLockWrite=0,
	xbLockRead=1
};

class xbEXPORT xbThreadEventObject;
interface sIxbThread;
interface sIxbExceptionCtx;
interface xbEXPORT __declspec(uuid("{4F119148-82EF-478f-B89F-0C597773D3FC}")) 
	sIxbThreadContextObject:public sIxbBase
{
	virtual void	ThreadContextRelease() = 0;
	virtual sIxbThreadContextObject *ThreadContextOld() = 0;
	virtual xbThreadEventObject *ThreadEvent() = 0;
	virtual bool onThreadShouldStop( ulong evMask ) const = 0;
	virtual bool	onThreadMsg(MSG *pMsg,bool *pbQuit) = 0;
}; 
interface xbEXPORT __declspec(uuid("{0AB50BEB-E375-45ad-B031-353E0DA62C61}")) 
	sIxbThreadContextFeeder:public sIxbBase
{
	virtual bool	ThreadContextCreate(const CLSID &clsid, sIxbThreadContextObject **ppObj) = 0; 
}; 

class xbThreadWaitLock;
class xbThreadWaitLockRW;
class xbEstack;
class xbEseh;
class xbThreadContext;

class xbEXPORT xbSectLockBaseRW
{
public:
	xbSectLockBaseRW()
	{
	}

	virtual void lockModeWriteNotif() = 0;
	virtual void lockMuteReadToWrite(xbThreadContext *pThCtx,xbSectShareBase *pShare) = 0;
};

class	xbEXPORT xbThreadContext
{
public:
	DWORD					m_id;					//Current Thread ID
	DWORD					m_rsrv0;

	HANDLE					m_shareEvent;
	
	LPCSTR					m_pName;					//Theorical name of Thread

	volatile xbThreadContext			*m_pThWaitPrev;
	volatile xbThreadContext			*m_pThWaitNext;

	sIxbThread				*m_pThread;
	sIxbExceptionCtx		*m_pExceptionCtx;

	sIxbThreadContextObject	*m_pExecCtx;
	sIxbThreadContextFeeder	*m_pExecCtxFeeder;

	xbEseh					*m_pCurEseh;
	xbEstack				*m_pCurEstack;
	xbThreadContext			*m_pThis;
	DWORD					m_rsrv2[5];

	xbLockMode				m_rwLockWaited;

	int						m_cShareStack;
	ulong					m_rsrv3;
	struct shareStackSt
	{
		xbSectShareBase		*m_pShare;
		xbSectLockBaseRW	*m_pLock;
		inline void set(xbSectShareBase *pShare)
		{
			m_pShare = pShare;
			m_pLock = NULL;
		}
		inline void set(xbSectShareBase *pShare, xbSectLockBaseRW *pLock)
		{
			m_pShare = pShare;
			m_pLock = pLock;
		}
	};
	shareStackSt			m_shareStack[xbStackShare_SIZEMAX];

	xbThreadContext( LPCSTR name, sIxbThread *pThread );
	~xbThreadContext( );

	void shareLeaveFind(xbSectShareBase *pShare);

#ifdef xbSectShareSTD_DEADLOCKDETECT
	void shareEnter(xbSectShareBase *pShare);
	void shareLeave(xbSectShareBase *pShare);
	void shareDeadLockCheck(ulong thidWaited,xbThreadWaitLock *pWaitLock);
#endif
	void shareEnterRW(xbSectShareBase *pShare, xbSectLockBaseRW *pLock);
	void shareLeaveRW(xbSectShareBase *pShare);
	bool shareLockMuteToWriteRW(xbSectShareBase *pShare);
#ifdef xbSectShareRW_DEADLOCKDETECT
	bool isShareEnteredRW(xbSectShareBase *pShare);
	void shareDeadLockCheckRW(xbSectShareBase *pShare,ulong thidWaited,xbLockMode mode,xbThreadWaitLockRW *pWaitLock);
#endif
//	void killCheck() {}
	HANDLE GetShareEvent() const {return m_shareEvent;}

public:
	LONG	GetThreadId			( ) {return m_id;}
	
	// Check if current thread has a valid xbThreadContext
	// If not, an exception occur
	void	AssertThreadCommitment( ) const;
	
	LPCSTR	GetName( )			{ return m_pName; }
	
	static xbThreadContext*	Current ( );
//	friend	xbSectShareBase;

	xbHeapDnewDclOnly(xbThreadContext);

private:
	xbDclNoCopyForObject(xbThreadContext);
};

inline LPCSTR xbGetCurrentThreadName(xbOpMode opm =xbOp_Required)
{
	xbThreadContext *pThCtx = xbThreadContext::Current();
	if (!pThCtx)
	{
		if (opm == xbOp_Required)
			xbThrowElock("Thread context not found !","xbGetCurrentThreadName()");
		return NULL;
	}
	return pThCtx->GetName();
}

inline xbThreadContext* xbGetCurrentThreadContext(xbOpMode opm =xbOp_Required)
{ 
	xbThreadContext *pThCtx = xbThreadContext::Current();
	if (opm == xbOp_Required && !pThCtx)
		xbThrowElock("Thread context not found !","xbGetCurrentThreadContext()");
	return pThCtx;
}

class xbEXPORT xbUseThreadContext
{
public:
	xbUseThreadContext()
	{
		m_pCtx = NULL;
	}
	xbUseThreadContext(LPCSTR pName)
	{
		m_pCtx = NULL;
		Start(pName);
	}
	~xbUseThreadContext()
	{
		eProtect(Stop());
	}
	void Start(LPCSTR pName)
	{
		if (m_pCtx)
			return;
		xbThreadContext *pTh;
		if ((pTh = xbThreadContext::Current()) != NULL)
		{
			if (pTh->m_pThis != pTh)
				xbThrowElockFmt("Invalid thread context !"
					"\1xbUseThreadContext::Start(%s)",(pName?pName:"[noname]"));
			return;
		}

		m_pCtx = xbDnew xbThreadContext(pName,NULL);
	}
	void Stop()
	{
		if (!m_pCtx)
			return;
		xbThreadContext *pCtx = m_pCtx;
		m_pCtx = NULL;
		delete pCtx;
	}
protected:
	xbThreadContext	*m_pCtx;
private:
	xbDclNoNewForObject(xbUseThreadContext);
	xbDclNoCopyForObject(xbUseThreadContext);
};

class xbCtxFeeder:public xbBase,public sIxbThreadContextFeeder
{
public:
	xbCtxFeeder(bool bCreate = true)
	{
		m_pOld = NULL;
		m_pThCtx = NULL;
		if (bCreate)
			Set();
	}
	virtual ~xbCtxFeeder()
	{
		if (m_pThCtx)
			eProtect(Unset());
	}
	void Set()
	{
		if (m_pThCtx)
			return;
		m_pThCtx = xbThreadContext::Current();
		if (!m_pThCtx)
			xbThrowElock("Thread context not found !");

		m_pOld = m_pThCtx->m_pExecCtxFeeder;
		m_pThCtx->m_pExecCtxFeeder = this;
	}
	void Unset()
	{
		if (!m_pThCtx)
			return;
		xbAssert(m_pThCtx == xbThreadContext::Current());

		m_pThCtx->m_pExecCtxFeeder = m_pOld;
		m_pThCtx = NULL;
	}
	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		xbImplInterface(sIxbThreadContextFeeder);
		return xbBase::GetInterface(riid,ppInterf);
	}

	virtual bool	ThreadContextCreate(const CLSID &clsid, sIxbThreadContextObject **ppObj)
	{
		if (onThreadContextCreate(clsid,ppObj))
			return true;
		if (!m_pOld)
			return false;
		return m_pOld->ThreadContextCreate(clsid,ppObj);
	}
protected:
	virtual bool	onThreadContextCreate(const CLSID &clsid, sIxbThreadContextObject **ppObj) = 0;

	sIxbThreadContextFeeder *m_pOld;
	xbThreadContext			*m_pThCtx;
};

template <class t_ctxItf, const IID* t_piid = &__uuidof(t_ctxItf)> 
class xbTctxGet
{
public:
	xbTctxGet(bool bCanCreate = true)
	{
		m_pCtx = NULL;
		m_pThEv = NULL;
		m_bCanCreate = bCanCreate;
		m_bToRelease = false;
	}
	virtual ~xbTctxGet()
	{
		if (m_bToRelease)
			eProtect(m_pCtx->ThreadContextRelease());
	}
	t_ctxItf *Get(xbOpMode opm =xbOp_Required)
	{
		if (m_pCtx)
			return m_pCtx;
		xbThreadContext *pThCtx = xbThreadContext::Current();
		if (!pThCtx)
		{
			if (opm == xbOp_Required)
				xbThrowElock("Thread context not found !");
			return NULL;
		}
	
		if (pThCtx->m_pExecCtx && xbCastIn<t_ctxItf>(pThCtx->m_pExecCtx,&m_pCtx))
		{
			m_pThEv = m_pCtx->ThreadEvent();
			return m_pCtx;
		}
		if (m_bCanCreate && pThCtx->m_pExecCtxFeeder)
		{
			sIxbThreadContextObject *pObj = NULL;
			if (pThCtx->m_pExecCtxFeeder->ThreadContextCreate(*t_piid,&pObj))
			{
				if (!pObj || !xbCastIn<t_ctxItf>(pObj,&m_pCtx))
				{
					if (pObj)
						pObj->ThreadContextRelease();

					xbThrowElock("Thread context feeder invalid !");
				}
				xbAssert(pThCtx->m_pExecCtx == pObj);

				m_bToRelease = true;
				m_pThEv = m_pCtx->ThreadEvent();
				return m_pCtx;
			}
		}
		
		if (opm == xbOp_Required)
			xbThrowElock("Thread context object not found !");
		return NULL;
	}
	void Reset(bool bCanCreate = true)
	{
		if (m_bToRelease)
			eProtect(m_pCtx->ThreadContextRelease());
		m_pCtx = NULL;
		m_pThEv = NULL;
		m_bCanCreate = bCanCreate;
		m_bToRelease = false;
	}
	virtual xbThreadEventObject *ThreadEvent()
	{
		return m_pThEv;
	}
	inline bool shouldStop() const
	{
		if (!m_pThEv)
			return false;
		ulong ev = m_pThEv->ProcessEvents();
		if (!ev)
			return false;
		return onThreadShouldStop(ev);
	}
	inline bool shouldStop(bool bNoStopSection) const
	{
		if (!m_pThEv)
			return false;
		if (bNoStopSection)
			return m_pThEv->ProcessToKill();
		ulong ev = m_pThEv->ProcessEvents();
		if (!ev)
			return false;
		return onThreadShouldStop(ev);
	}
	inline bool shouldKill() const
	{
		if (!m_pThEv)
			return false;
		return m_pThEv->ProcessToKill();
	}
	void checkStop() const
	{
		if (!shouldStop())
			return;
		xbThrow xbEuser(E_ABORT,"Operation cancelled");
	}
	void checkStop(const xbString &oplabel) const
	{
		if (!shouldStop())
			return;
		xbThrow xbEuser(E_ABORT,oplabel+" cancelled");
	}
	bool	onThreadMsg(MSG *pMsg,bool *pbQuit)
	{
		t_ctxItf *pItf = Get(xbOp_Optional);
		if (!pItf)
			return false;
		return pItf->onThreadMsg(pMsg,pbQuit);
	}

protected:
	bool onThreadShouldStop( ulong evMask ) const
	{
		return m_pCtx->onThreadShouldStop(evMask);
	}
protected:
	t_ctxItf				*m_pCtx;
	xbThreadEventObject		*m_pThEv;
	bool					m_bCanCreate,m_bToRelease;
};

class xbEXPORT xbCtxBase:public xbBase,public sIxbThreadContextObject
{
public:
	xbCtxBase()
	{
		m_pThCtxObjOld = NULL;
		m_pThCtx = NULL;
		m_pThEv = NULL;
	}
	virtual ~xbCtxBase()
	{
		if (!m_pThCtx)
			return;
		eProtect(RemoveFromThreadCtx());
	}
	void AddToThreadCtx()
	{
		if (m_pThCtx)
			return;
		m_pThCtx = xbThreadContext::Current();
		if (!m_pThCtx)
			xbThrowElock("Thread context not found !");

		m_pThCtxObjOld = m_pThCtx->m_pExecCtx;
		m_pThCtx->m_pExecCtx = this;
		m_pThEv = m_pThCtxObjOld?m_pThCtxObjOld->ThreadEvent():NULL;
	}
	void RemoveFromThreadCtx()
	{
		if (!m_pThCtx)
			return;
		xbAssert(m_pThCtx == xbThreadContext::Current());

		m_pThCtx->m_pExecCtx = m_pThCtxObjOld;
		m_pThCtx = NULL;
		m_pThEv = NULL;
	}
	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		xbImplInterface(sIxbThreadContextObject);

		if (m_pThCtxObjOld)
			return m_pThCtxObjOld->GetInterface(riid,ppInterf);

		return xbBase::GetInterface(riid,ppInterf);
	}

	virtual void	ThreadContextRelease()
	{
		delete this;
	}
	virtual sIxbThreadContextObject *ThreadContextOld()
	{
		return m_pThCtxObjOld;
	}
	virtual xbThreadEventObject *ThreadEvent()
	{
		return m_pThEv;
	}
	void checkStop() const;
	void checkStop(const xbString &oplabel) const;
	inline bool shouldStop() const
	{
		if (!m_pThEv)
			return false;
		ulong ev = m_pThEv->ProcessEvents();
		if (!ev)
			return false;
		return onThreadShouldStop(ev);
	}
	inline bool shouldStop(bool bNoStopSection) const
	{
		if (!m_pThEv)
			return false;
		if (bNoStopSection)
			return m_pThEv->ProcessToKill();
		ulong ev = m_pThEv->ProcessEvents();
		if (!ev)
			return false;
		return onThreadShouldStop(ev);
	}
	inline bool shouldKill() const
	{
		if (!m_pThEv)
			return false;
		return m_pThEv->ProcessToKill();
	}

	virtual bool onThreadShouldStop( ulong evMask ) const
	{
		if (m_pThCtxObjOld
			&& m_pThCtxObjOld->onThreadShouldStop(evMask))
			return true;
		return (evMask & (xbTHREADEVENT_KILL|xbTHREADEVENT_STOP|xbTHREADEVENT_STOPTASK))?true:false;
	}
	virtual bool onThreadMsg(MSG *pMsg,bool *pbQuit)
	{
		if (m_pThCtxObjOld
			&& m_pThCtxObjOld->onThreadMsg(pMsg,pbQuit))
			return true;
		return false;
	}

	xbHeapDnewDclOnly(xbCtxBase);
private:
	xbDclNoCopyForObject(xbCtxBase);

protected:

	sIxbThreadContextObject *m_pThCtxObjOld;
	xbThreadContext			*m_pThCtx;
	xbThreadEventObject		*m_pThEv;
};

xbEXPORT typedef xbTctxGet<sIxbThreadContextObject> xbCtxGet;

enum xbProgressStatus
{
	xbProgressIn,
	xbProgressSuspended,
	xbProgressErrorDone,
	xbProgressWellDone
};

interface sIxbProgressReport;
interface xbEXPORT __declspec(uuid("{04551C29-E760-480f-9FCD-65C1D7CE34A2}")) 
	sIxbProgressInfo:public sIxbThreadContextObject
{
	virtual bool stageInfoGet(int no,xbString *pName,xbString *pLabel, uint64 *pStep, uint64 *pStepCnt, xbString *pUnit,xbProgressStatus *pStatus, xbString *pStatusTxt) = 0;
	virtual bool stageErrorGet(int no,LPCSTR pName,xbString *pMsg,xbString *pCtx,LPCSTR pFmt) = 0;
	virtual int stageInfoLength() const = 0;
	virtual sIxbProgressReport *GetProgressReport() = 0;
}; 

interface xbEXPORT __declspec(uuid("{BE5DC310-DBF0-4c5d-8E28-01AEDC752A1F}")) 
	sIxbProgressReport
{
	virtual void stageStarted(sIxbProgressInfo *pPrgInfo,bool bMainStage) = 0;
	virtual void stageChanged(sIxbProgressInfo *pPrgInfo,bool bMainStage) = 0;
	virtual void stageInError(sIxbProgressInfo *pPrgInfo,bool bMainStage) = 0;
	virtual void stageEnded(sIxbProgressInfo *pPrgInfo,bool bMainStage) = 0;
}; 

interface xbEXPORT __declspec(uuid("{39B4252D-0A4C-4842-8DB2-9A6055C63D61}")) 
	sIxbProgress:public sIxbProgressInfo
{
	virtual void stageStart(LPCSTR pName, LPCSTR pLabel, uint64 stepCnt, LPCSTR pUnit) = 0;
	virtual void stageStatus(LPCSTR pName, xbProgressStatus status, LPCSTR pStatus) = 0;
	virtual void stageStep(LPCSTR pName, uint64 step, LPCSTR pUnit, bool bAddStep = false) = 0;
	virtual void stageStepCount(LPCSTR pName, uint64 stepCnt, LPCSTR pUnit, bool bAddStepCnt = false) = 0;
	virtual void stageEnd(LPCSTR pName) = 0;
	virtual void stageError(LPCSTR pName,xbEbase *pE,LPCSTR pMsg,bool bEdel = false) = 0;
}; 

#ifdef xbSectShareBase_DEADLOCKPREVENT
class xbSectShareDeadInfo;

#define xbSectShareBaseDEAD_DISABLED	0x80000000
#define xbSectShareBaseDEAD_PRIORALL	0x40000000
#define xbSectShareBaseDEAD_FINAL		0x20000000
#define xbSectShareBaseDEAD_BEFOREPRIOR	0x10000000

#define xbSectShareBaseDEAD_ORDERTYPE	0x0FFFFF00
#define xbSectShareBaseDEAD_ORDERVAL	0x000000FF
#endif

class xbEXPORT xbSectShareBase
{
protected:
	xbSectShareSimple			m_thListShare;
	volatile xbThreadContext	*m_pThWaitingFirst;
	volatile xbThreadContext	*m_pThWaitingLast;
#ifdef xbSectShareBase_DEADLOCKPREVENT
	ulong				m_id;
	ulong				m_deadStatus;
	static ulong		s_idcurrent;
	xbSectShareDeadInfo	*m_pDeadInfo;	
	friend xbSectShareDeadInfo;
#endif
	friend xbThreadContext;
public:
	xbSectShareBase()
	{
		m_pThWaitingFirst=NULL;
		m_pThWaitingLast=NULL;
#ifdef xbSectShareBase_DEADLOCKPREVENT
		m_id = ++s_idcurrent;
		m_pDeadInfo = NULL;	
		m_deadStatus = 0;
#	ifdef XDCBASE_X64
		xbRdbgAssert(sizeof(xbSectShareBase)==40);
#	else
		xbRdbgAssert(sizeof(xbSectShareBase)==24);
#	endif
#else
#	ifdef XDCBASE_X64
		xbRdbgAssert(sizeof(xbSectShareBase)==24);
#	else
		xbRdbgAssert(sizeof(xbSectShareBase)==12);
#	endif
#endif
	}
#ifdef xbSectShareBase_DEADLOCKPREVENT
	~xbSectShareBase();
	inline void DeadLockPreventDisable()
	{
		m_deadStatus|=xbSectShareBaseDEAD_DISABLED;
	}
	inline void DeadLockOrderPriorAll()
	{
		m_deadStatus|=xbSectShareBaseDEAD_PRIORALL;
	}
	inline void DeadLockOrderBeforePriorAll()
	{
		m_deadStatus|=xbSectShareBaseDEAD_BEFOREPRIOR;
	}
	inline void DeadLockOrderFinal()
	{
		m_deadStatus|=xbSectShareBaseDEAD_FINAL;
	}
	inline void DeadLockOrderDef(ulong familly, ulong order)
	{
		xbRdbgAssert(
			!(m_deadStatus&(xbSectShareBaseDEAD_ORDERTYPE|xbSectShareBaseDEAD_ORDERVAL))
			||(m_deadStatus&(xbSectShareBaseDEAD_ORDERTYPE|xbSectShareBaseDEAD_ORDERVAL))==(((familly<<8)&xbSectShareBaseDEAD_ORDERTYPE)|(order & xbSectShareBaseDEAD_ORDERVAL)));
		if (m_deadStatus&(xbSectShareBaseDEAD_ORDERTYPE|xbSectShareBaseDEAD_ORDERVAL))
			return;

		m_deadStatus|=((familly<<8)&xbSectShareBaseDEAD_ORDERTYPE)
			| (order & xbSectShareBaseDEAD_ORDERVAL);
	}
	inline void DeadLockOrderDefForce(ulong familly, ulong order)
	{
		if (m_deadStatus&(xbSectShareBaseDEAD_ORDERTYPE|xbSectShareBaseDEAD_ORDERVAL))
			m_deadStatus &= ~(xbSectShareBaseDEAD_ORDERTYPE|xbSectShareBaseDEAD_ORDERVAL);

		m_deadStatus|=((familly<<8)&xbSectShareBaseDEAD_ORDERTYPE)
			| (order & xbSectShareBaseDEAD_ORDERVAL);
	}
	inline bool lockOrderStatusOk(xbSectShareBase *pShareBefore)
	{
		if (!(m_deadStatus&xbSectShareBaseDEAD_ORDERTYPE)
			||!(pShareBefore->m_deadStatus&xbSectShareBaseDEAD_ORDERTYPE))
			return true;
		return (m_deadStatus&xbSectShareBaseDEAD_ORDERVAL) >= (pShareBefore->m_deadStatus&xbSectShareBaseDEAD_ORDERVAL);
	}
	void lockOrderStatusCheck(xbSectShareBase *pShareBefore);
#else
	inline void DeadLockPreventDisable()
	{
	}
	inline void DeadLockOrderPriorAll()
	{
	}
	inline void DeadLockOrderBeforePriorAll()
	{
	}
	inline void DeadLockOrderFinal()
	{
	}
	inline void DeadLockOrderDef(ulong, ulong)
	{
	}
	inline void DeadLockOrderDefForce(ulong, ulong)
	{
	}
#endif
	void waitLink(xbThreadContext *pThCtx);
	void waitUnlink(xbThreadContext *pThCtx, bool bSignalNext);
	void waitSignal();
	bool waitedByThread(ulong thid);
#ifdef xbSectShareSTD_DEADLOCKPREVENT
	void dlpLockedAfterCheck(xbSectShareBase *pShareBefore);
	void dlpLockedBefore(xbSectShareBase *pShareAfter);
#endif
#ifdef xbSectShareRW_DEADLOCKPREVENT
	void dlpLockedAfterCheckRW(xbSectShareBase *pShareBefore);
	void dlpLockedBeforeRW(xbSectShareBase *pShareAfter);
#endif

	xbString lockInfo(xbThreadContext *pThCtx = NULL);
private:
	xbDclNoCopyForObject(xbSectShareBase);
};

class xbThreadWaitLock
{
protected:
	HANDLE			m_hEv;
	xbSectShareBase *m_pShare;
	xbThreadContext *m_pThCtx;
#ifdef xbSectShareSTD_DEADLOCKDETECT
	bool			m_bDeadLockCheck;
#endif
	friend xbThreadContext;
public:
	xbThreadWaitLock()
	{
		m_hEv=NULL;
	}
	xbThreadWaitLock(xbThreadContext *pThCtx,xbSectShareBase *pShare)
	{
		m_hEv=NULL;
		Lock(pThCtx,pShare);
	}
	void Lock(xbThreadContext *pThCtx,xbSectShareBase *pShare)
	{
		xbRdbgAssert(!m_hEv);
		if (m_hEv || !pThCtx)
			return;

		HANDLE hEv = pThCtx->GetShareEvent();
		pShare->waitLink(pThCtx);
		m_pShare = pShare;
		m_pThCtx = pThCtx;
		m_hEv = hEv;
#ifdef xbSectShareSTD_DEADLOCKDETECT
		m_bDeadLockCheck=true;
#endif
	}
	bool IsWaitLocked() const {return m_hEv != NULL;}
/*	HANDLE GetShareEvent()
	{
		xbRdbgAssert(m_hEv);
		return m_hEv;
	}*/
#ifdef xbSectShareSTD_DEADLOCKDETECT
	void DeadLockCheck(ulong thidWaited)
	{
		if (!m_bDeadLockCheck || !m_hEv)
			return;
		m_pThCtx->shareDeadLockCheck(thidWaited,this);
		m_bDeadLockCheck = false;
	}
#endif
	ulong Wait(ulong millisec)
	{
		HANDLE hEv = m_hEv;
		if (!hEv)
			return WAIT_OBJECT_0;

#ifdef xbSectShareSTD_DEADLOCKDETECT
		if (m_bDeadLockCheck)
		{
			if (millisec > xbStackShare_CHECKTIMEMAX)
				millisec = xbStackShare_CHECKTIMEMAX;
		}
		else
#endif
		{
			if (millisec > xbStackShare_WAITTIMEMAX)
				millisec = xbStackShare_WAITTIMEMAX;
		}
		return ::WaitForSingleObject(hEv,millisec);
	}
	void Abort()
	{
		if (!m_hEv)
			return;
		m_hEv=NULL;
		m_pShare->waitUnlink(m_pThCtx, true);
	}
	void Unlock()
	{
		if (!m_hEv)
			return;
		m_hEv=NULL;
		m_pShare->waitUnlink(m_pThCtx, false);
	}
	~xbThreadWaitLock()
	{
		eProtect(Unlock());
	}
};

class xbEXPORT xbSectShareSpin:public xbSectShareBase
{
protected:
	volatile ulong	m_thid;
	ulong			m_cLock;
public:
	/*
	CRITICAL_SECTION x64 -> 40, x86 -> 24
	gpLockSection x64 -> 32, x86 -> 20
	*/
	xbSectShareSpin()
		:m_thid(0),m_cLock(0)
	{
#ifdef xbSectShareSTD_STAT
#	ifdef xbSectShareBase_DEADLOCKPREVENT
#		ifdef XDCBASE_X64
			xbRdbgAssert(sizeof(xbSectShareSpin)==56);
#		else
			xbRdbgAssert(sizeof(xbSectShareSpin)==36);
#		endif
#	else
#		ifdef XDCBASE_X64
			xbRdbgAssert(sizeof(xbSectShareSpin)==40);
#		else
			xbRdbgAssert(sizeof(xbSectShareSpin)==24);
#		endif
#	endif
#else
#	ifdef xbSectShareBase_DEADLOCKPREVENT
#		ifdef XDCBASE_X64
			xbRdbgAssert(sizeof(xbSectShareSpin)==48);
#		else
			xbRdbgAssert(sizeof(xbSectShareSpin)==32);
#		endif
#	else
#		ifdef XDCBASE_X64
			xbRdbgAssert(sizeof(xbSectShareSpin)==32);
#		else
			xbRdbgAssert(sizeof(xbSectShareSpin)==20);
#		endif
#	endif
#endif
	}
	~xbSectShareSpin()
	{
		xbRdbgAssert(!m_thid && !m_cLock);
	}
	void Lock()
	{
		ulong thid = ::xbThreadId();
		if (m_thid == thid)
		{
			m_cLock++;
			return;
		}

		if (!m_thid && xbInterlockCompareExchange32((long*)&m_thid,thid,0) == 0)
		{
#ifdef xbSectShare_DEBUG
			if (m_thid != thid || m_cLock)
				xbThrowElockFmt("Waiting for object operation failure, bad thread id or lock count"
				"\1xbSectShareSpin::Lock(): cLock=%lu, thid=%lX, m_thid=%lX",
				m_cLock,thid,m_thid);
#endif
			m_cLock++;
#ifdef xbSectShareSTD_DEADLOCKDETECT
			xbThreadContext		*pThCtx = xbThreadContext::Current();
			if (pThCtx)
				pThCtx->shareEnter(this);
#endif
			return;
		}

		longLock(thid);
	}
protected:
	void longLock(ulong thid);
public:
	void Unlock()
	{
		ulong thid = ::xbThreadId();
#ifdef xbSectShare_DEBUG
		if (m_thid != thid)
			xbThrowElockFmt("Unlock operation invalid"
			"\1xbSectShareSpin::Unlock(): bad thid (m_thid: %lX != thid: %lX)",
			m_thid,thid);
		if (m_cLock <= 0)
			xbThrowElockFmt("Unlock operation invalid"
			"\1xbSectShareSpin::Unlock(): bad lock count (m_thid=%lX, thid=%lX, cLock=%lu)",
			m_thid,thid,m_cLock);
#endif
		if (--m_cLock)
			return;

#ifdef xbSectShareSTD_DEADLOCKDETECT
		xbThreadContext		*pThCtx = xbThreadContext::Current();
		if (pThCtx)
			pThCtx->shareLeave(this);
#endif

		_WriteBarrier(); //compiler optim only: prevent reordering, changes done to the shared resource are committed.

		m_thid = 0;

		_ReadWriteBarrier(); //compiler optim only: prevent reordering

		if (m_pThWaitingLast)
			waitSignal();
	}
	bool TryLock()
	{
		ulong thid = ::xbThreadId();
		if (m_thid == thid)
		{
			m_cLock++;
			return true;
		}

		if (m_thid || xbInterlockCompareExchange32((long*)&m_thid,thid,0) != 0)
			return false;

#ifdef xbSectShare_DEBUG
		if (m_thid != thid || m_cLock)
			xbThrowElockFmt("Waiting for object operation failure, bad thread id or lock count"
				"\1xbSectShareSpin::TryLock(): cLock=%lu, thid=%lX, m_thid=%lX",
				m_cLock,thid,m_thid);
#endif
		m_cLock++;
#ifdef xbSectShareSTD_DEADLOCKDETECT
		xbThreadContext		*pThCtx = xbThreadContext::Current();
		if (pThCtx)
			pThCtx->shareEnter(this);
#endif

		return true;
	}

	bool IsWaited() const 
	{
		return m_pThWaitingFirst!=NULL;
	}
	bool	IsLockedByMe() const
	{
		return m_cLock>0 && m_thid == ::xbThreadId();
	}
	bool	IsLockedByAny() const
	{
		return m_cLock>0;
	}
#ifdef xbSectShareSTD_STAT
protected:
	virtual void onThreadWaitTime(ulong tiStart) {}
#endif
private:
	xbDclNoCopyForObject(xbSectShareSpin);
};

class xbSectLockSpin
{
public:
	xbSectLockSpin()
	{
		m_pSect = NULL;
	}
	xbSectLockSpin(xbSectShareSpin *pSect)
	{
		m_pSect = NULL;
		Lock(pSect);
	}
	~xbSectLockSpin()
	{
		eProtect(Unlock());
	}
	void Lock(xbSectShareSpin *pSect)
	{
		if (pSect == m_pSect)
			return;
		if (m_pSect) Unlock();
		if (pSect) pSect->Lock();
		m_pSect = pSect;
	}
	void Unlock()
	{
		if (!m_pSect) return;
		xbSectShareSpin	*pSect = m_pSect;
		m_pSect = NULL;
		pSect->Unlock();
	}
	bool TryLock(xbSectShareSpin *pSect)
	{
		if (pSect == m_pSect)
			return true;
		if (m_pSect) Unlock();
		if (pSect && !pSect->TryLock())
			return false;
		m_pSect = pSect;
		return true;
	}
	bool IsLocked() const {return m_pSect != NULL;}
	const xbSectShareSpin *getLock() const {return m_pSect;}
protected:
	xbSectShareSpin		*m_pSect;
private:
	xbDclNoCopyForObject(xbSectLockSpin);
};

typedef xbSectShareSpin xbSectShare;
typedef xbSectLockSpin xbSectLock;

inline void xbCritSectExTestSys(BOOL bFailed)
{
	if (bFailed)
		xbThrowElock(xbHR_LAST,"xbCritSectEx lock error");
}

class xbEXPORT xbCritSectEx 
{
//	static DWORD s_dwProcessors;

	// Declare all variables volatile, so that the compiler won't
	// try to optimize something important.
	volatile DWORD	m_nLocker;
	volatile DWORD	m_dwSpinMax;
	volatile HANDLE	m_hSemaphore;
	volatile long	m_nWaiters;

	// disable copy constructor and assignment
	xbCritSectEx(const xbCritSectEx&);
	void operator = (const xbCritSectEx&);

	inline bool PerfLockImmediate(DWORD dwThreadID)
	{
		return !xbInterlockCompareExchange32((long*) &m_nLocker, dwThreadID, 0);
	}
	inline void WaiterPlus()
	{
		xbInterlockIncrement32(&m_nWaiters);
	}
	inline void WaiterMinus()
	{
		xbInterlockDecrement32(&m_nWaiters);
	}

	bool PerfLock(DWORD dwThreadID, DWORD dwTimeout);
	bool PerfLockKernel(DWORD dwThreadID, DWORD dwTimeout);

	void PerfUnlock()
	{
		_WriteBarrier(); // changes done to the shared resource are committed.

		m_nLocker = 0;

		_ReadWriteBarrier(); // The CS is released.

		if (m_nWaiters > 0) // AFTER it is released we check if there're waiters.
		{
			WaiterMinus();

			xbAssert(m_hSemaphore);
			xbCritSectExTestSys(!ReleaseSemaphore(m_hSemaphore, 1, NULL));
		}
	}

public:
	// Constructor/Destroctor
	xbCritSectEx()
	{
		ZeroMemory(this, sizeof(*this));
	}
	xbCritSectEx(DWORD dwSpinMax)
	{
		ZeroMemory(this, sizeof(*this));
		SetSpinMax(dwSpinMax);
	}
	~xbCritSectEx()
	{
		if (m_hSemaphore)
			xbMustBe(CloseHandle(m_hSemaphore));
	}

	// Lock/Unlock
	bool Lock(bool& bUnlockFlag, DWORD dwTimeout = INFINITE)
	{
		DWORD dwThreadId = xbThreadId();
		if (dwThreadId == m_nLocker)
			bUnlockFlag = false;
		else
			if ((!m_nLocker && PerfLockImmediate(dwThreadId)) ||
				(dwTimeout && PerfLock(dwThreadId, dwTimeout)))
				bUnlockFlag = true;
			else
				return false;

		return true;
	}
	void Unlock(bool bUnlockFlag)
	{
		if (bUnlockFlag)
			PerfUnlock();
	}

	// Some extra
	void SetSpinMax(DWORD dwSpinMax);
	void AllocateKernelSemaphore();

	// Scope
	class Scope {

		// disable copy constructor and assignment
		Scope(const Scope&);
		void operator = (const Scope&);

		xbCritSectEx* m_pCs;
		bool m_bLocked;
		bool m_bUnlockFlag;

		void InternalUnlock()
		{
			if (m_bUnlockFlag)
			{
				xbAssert(m_pCs);
				m_pCs->PerfUnlock();
			}
		}
		void InternalLock(DWORD dwTimeout)
		{
			xbAssert(m_pCs);
			m_bLocked = m_pCs->Lock(m_bUnlockFlag, dwTimeout);
		}
		void InternalLock(xbCritSectEx& cs, DWORD dwTimeout)
		{
			m_bUnlockFlag = false;
			m_pCs = &cs;
			InternalLock(dwTimeout);
		}

	public:
		Scope()
			:m_bLocked(false)
			,m_bUnlockFlag(false)
			,m_pCs(NULL)
		{
		}
		Scope(xbCritSectEx& cs, DWORD dwTimeout = INFINITE)
		{
			InternalLock(cs, dwTimeout);
		}
		~Scope()
		{
			InternalUnlock();
		}

		bool Lock(xbCritSectEx& cs, DWORD dwTimeout = INFINITE)
		{
			if (&cs == m_pCs)
				return Lock(dwTimeout);

			InternalUnlock();
			InternalLock(cs, dwTimeout);
			return m_bLocked;
		}
		bool Lock(DWORD dwTimeout = INFINITE)
		{
			xbAssert(m_pCs);
			if (!m_bLocked)
				InternalLock(dwTimeout);
			return m_bLocked;
		}
		void Unlock()
		{
			InternalUnlock();
			m_bUnlockFlag = false;
			m_bLocked = false;
		}

		bool IsLocked() const { return m_bLocked; }
		operator bool () const { return m_bLocked; }
	};
	friend class Scope;
};

// Classical critical sections, with internal support for recursive locks counter.
class xbEXPORT xbCritSectRec 
{
	xbCritSectEx m_cs;
	long m_nRecursion;

	// disable copy constructor and assignment
	xbCritSectRec(const xbCritSectRec&);
	void operator = (const xbCritSectRec&);

public:
	xbCritSectRec()
		:m_nRecursion(0)
	{
	}

	bool Lock(DWORD dwTimeout = INFINITE)
	{
		bool bUnlockFlag;
		if (!m_cs.Lock(bUnlockFlag, dwTimeout))
			return false;

		xbAssert(bUnlockFlag ? !m_nRecursion : (m_nRecursion > 0));
		m_nRecursion++;
		return true;
	}
	bool TryEnter()
	{
		return Lock(0);
	}
	void Unlock()
	{
		xbAssert(m_nRecursion > 0);
		if (! --m_nRecursion)
			m_cs.Unlock(true);
	}

	// Some extra
	void SetSpinMax(DWORD dwSpinMax) { m_cs.SetSpinMax(dwSpinMax); }
	void AllocateKernelSemaphore() { m_cs.AllocateKernelSemaphore(); }

	struct Scope 
	{

		// disable copy constructor and assignment
		Scope(const Scope&);
		void operator = (const Scope&);

		xbCritSectRec* m_pCs;
		bool m_bLocked;

		void InternalLeave()
		{
			if (m_bLocked)
			{
				xbAssert(m_pCs);
				m_pCs->Unlock();
			}
		}
		void InternalEnter(DWORD dwTimeout)
		{
			xbAssert(m_pCs);
			m_bLocked = m_pCs->Lock(dwTimeout);
		}
		void InternalEnter(xbCritSectRec& cs, DWORD dwTimeout)
		{
			m_pCs = &cs;
			InternalEnter(dwTimeout);
		}

	public:
		Scope()
			:m_bLocked(false)
			,m_pCs(NULL)
		{
		}
		Scope(xbCritSectRec& cs, DWORD dwTimeout = INFINITE)
		{
			InternalEnter(cs, dwTimeout);
		}
		~Scope()
		{
			InternalLeave();
		}

		bool Enter(xbCritSectRec& cs, DWORD dwTimeout = INFINITE)
		{
			if (&cs == m_pCs)
				return Enter(dwTimeout);

			InternalLeave();
			InternalEnter(cs, dwTimeout);
			return m_bLocked;
		}
		bool Enter(DWORD dwTimeout = INFINITE)
		{
			xbAssert(m_pCs);
			if (!m_bLocked)
				InternalEnter(dwTimeout);
			return m_bLocked;
		}
		void Leave()
		{
			InternalLeave();
			m_bLocked = false;
		}

		bool IsLocked() const { return m_bLocked; }
		operator bool () const { return m_bLocked; }
	};
};


#endif 
