WCSpace.h
// WCSpace.h
//
// A wrapper on CSpace that adds thread affinity.
//
// David Barrett-Lennard
//
// (C)opyright Cedanet Pty Ltd 2007
@import "cxObject.h"
@import "IObject.h"
@import "ThreadPtr.h"
@import "CSpace.h"
#include <exception>
///////////////////////////////////////////////////////////////////////////////////////////////////
// Per thread pointer to the CSpace currently affiliated with the thread
/*
Thread local storage is used to allow each thread to store a pointer to a CSpace to which it is
currently affiliated. Some of the functions in this header work implicitly on the affiliate CSpace
of the calling thread.
A newly created thread has a nullptr affiliate CSpace, and therefore it is an error to call any of
the functions that require an affiliate CSpace.
*/
namespace ceda
{
// Set/Get the pointer to the CSpace currently affiliated with the calling thread.
// Returns nullptr if there is no affiliate CSpace.
mDefineThreadPtr(CSpace)
#ifdef CEDA_CHECK_ASSERTIONS
inline bool HaveLockedCSpace()
{
return HaveRecordedLock(GetThreadPtr<CSpace>());
}
// The following functions assert:
// 1) the given object is not null
// 2) the given object is registered in a CSpace
// 3) the CSpace associated with the object is set in TLS
@api bool HaveLockedCSpace(ptr<const IObject> p);
#endif // CEDA_CHECK_ASSERTIONS
// Returns true if p is associated with this thread's associated CSpace.
// Assumes p is not null.
$function+ bool ObjectInThreadCSpace(ptr<const IObject> p);
///////////////////////////////////////////////////////////////////////////////////////////////////
// Garbage collection
/*
All the following functions work implicitly on the CSpace affiliated with the calling thread.
It is an error to call these functions if there is no affiliate CSpace.
*/
$function+ void AddGcRoot(ptr<const IObject> object);
$function+ void RemoveGcRoot(ptr<const IObject> object);
$function+ void StartGc();
$function+ void StopGc();
$function+ void SynchronousGc();
$function+ int32 GetMilliSecsPerGc();
$function+ void SetMilliSecsPerGc(int32 t);
$function+ ssize_t GetMaxDgsTotalByteSize(ssize_t evictionQueueIndex);
$function+ void SetMaxDgsTotalByteSize(ssize_t evictionQueueIndex, ssize_t totalSizeInBytes);
$function+ ssize_t GetEvictionThreshold();
$function+ void SetEvictionThreshold(ssize_t totalSizeInBytes);
#ifdef CEDA_CHECK_ASSERTIONS
class CSpacePseudoLock
{
public:
CSpacePseudoLock() : cs_(GetThreadPtr<CSpace>())
{
RecordCSpaceLock(cs_);
}
explicit CSpacePseudoLock(CSpace* cs) : cs_(cs)
{
RecordCSpaceLock(cs_);
}
~CSpacePseudoLock()
{
RecordCSpaceUnlock(cs_);
}
private:
CSpace* cs_;
};
#endif // CEDA_CHECK_ASSERTIONS
///////////////////////////////////////////////////////////////////////////////////////////////////
// CSpaceCreator
// Declared on the frame to create a CSpace and set it as the affilliate CSpace for the calling
// thread
// TODO: the name of this class seems illogical, the destructor destroys it!
class CSpaceCreator : public DeclareThreadPtr<CSpace>
{
public:
explicit CSpaceCreator(int32 milliSecsPerGC = CEDA_DEFAULT_MILLISECS_PER_GC)
{
cs_ = CreateCSpace(milliSecsPerGC);
SetThreadPtr<CSpace>(cs_);
}
~CSpaceCreator()
{
Destroy(cs_);
}
operator CSpace*() { return cs_; }
private:
CSpace* cs_;
};
///////////////////////////////////////////////////////////////////////////////////////////////////
// CSpaceLock
// Declared on the frame to lock a single CSpace
class CSpaceLock
{
cxNotCloneable(CSpaceLock)
public:
CSpaceLock(CSpace* cs, ECSpaceLockMode mode = ECSpaceLockMode::Exclusive) :
cs_(cs)
{
cxAssert(cs_);
Lock(cs_, mode);
}
explicit CSpaceLock(ECSpaceLockMode mode = ECSpaceLockMode::Exclusive) :
cs_(GetThreadPtr<CSpace>())
{
cxAssert(cs_);
Lock(cs_, mode);
}
~CSpaceLock()
{
/*
if (uncaughtExceptionCount_ != std::uncaught_exceptions())
{
// Stack is unwinding, we assume it is too risky to allow
// a transaction to commit, and instead terminate the process
cxAlwaysAssert( false );
std::terminate();
}
*/
Unlock(cs_);
}
private:
CSpace* cs_;
//int uncaughtExceptionCount_ = std::uncaught_exceptions();
};
///////////////////////////////////////////////////////////////////////////////////////////////////
// CSpaceTxn
struct CSpaceTxn : CSpaceLock
{
explicit CSpaceTxn(CSpace* cs) : CSpaceLock(cs,ECSpaceLockMode::Transaction) {}
CSpaceTxn() : CSpaceLock(ECSpaceLockMode::Transaction) {}
};
///////////////////////////////////////////////////////////////////////////////////////////////////
// CSpaceRelinquishLock
class CSpaceRelinquishLock
{
cxNotCloneable(CSpaceRelinquishLock)
public:
explicit CSpaceRelinquishLock(CSpace* cs = GetThreadPtr<CSpace>()) :
cs_(cs)
{
cxAssert(cs_);
li_ = BeginUnlock(cs_);
}
~CSpaceRelinquishLock()
{
EndUnlock(cs_,li_);
}
private:
CSpace* cs_;
LockInfo li_;
};
///////////////////////////////////////////////////////////////////////////////////////////////////
// LocalCSpace
struct @api LocalCSpace
{
LocalCSpace();
~LocalCSpace();
CSpace* m_child;
CSpace* m_parent;
LocalCSpace* m_prevLocal;
};
///////////////////////////////////////////////////////////////////////////////////////////////////
// LockAndTransfer
struct @api LockAndTransfer
{
LockAndTransfer();
~LockAndTransfer();
LocalCSpace* m_lc;
};
}