mirror of
https://github.com/0TheSpy/Seaside.git
synced 2025-01-11 11:33:01 +08:00
948 lines
19 KiB
C
948 lines
19 KiB
C
|
#ifndef TSLIST_H
|
||
|
#define TSLIST_H
|
||
|
|
||
|
#if defined( _WIN32 )
|
||
|
#pragma once
|
||
|
#pragma warning( push )
|
||
|
#pragma warning( disable : 4700 )
|
||
|
#endif
|
||
|
|
||
|
#if defined( USE_NATIVE_SLIST ) && !defined( _X360 )
|
||
|
#define WIN32_LEAN_AND_MEAN
|
||
|
#include <windows.h>
|
||
|
#endif
|
||
|
|
||
|
#include "dbg.h"
|
||
|
#include "threadtools.h"
|
||
|
#include "memalloc.h"
|
||
|
#include "memdbgoff.h"
|
||
|
|
||
|
#if defined( _X360 )
|
||
|
#define USE_NATIVE_SLIST
|
||
|
#endif
|
||
|
|
||
|
#if defined( PLATFORM_64BITS )
|
||
|
|
||
|
#if defined (PLATFORM_WINDOWS)
|
||
|
#else
|
||
|
typedef __int128_t int128;
|
||
|
#define int128_zero() 0
|
||
|
#endif
|
||
|
|
||
|
#define TSLIST_HEAD_ALIGNMENT 16
|
||
|
#define TSLIST_NODE_ALIGNMENT 16
|
||
|
|
||
|
#ifdef POSIX
|
||
|
inline bool ThreadInterlockedAssignIf128(int128 volatile* pDest, const int128& value, const int128& comparand)
|
||
|
{
|
||
|
int128 local_comparand = comparand;
|
||
|
return __sync_bool_compare_and_swap(pDest, local_comparand, value);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
inline bool ThreadInterlockedAssignIf64x128(volatile int128* pDest, const int128& value, const int128& comperand)
|
||
|
{
|
||
|
return ThreadInterlockedAssignIf128(pDest, value, comperand);
|
||
|
}
|
||
|
#else
|
||
|
#define TSLIST_HEAD_ALIGNMENT 8
|
||
|
#define TSLIST_NODE_ALIGNMENT 8
|
||
|
inline bool ThreadInterlockedAssignIf64x128(volatile int64* pDest, const int64 value, const int64 comperand)
|
||
|
{
|
||
|
return ThreadInterlockedAssignIf64(pDest, value, comperand);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef _MSC_VER
|
||
|
#define TSLIST_HEAD_ALIGN DECL_ALIGN(TSLIST_HEAD_ALIGNMENT)
|
||
|
#define TSLIST_NODE_ALIGN DECL_ALIGN(TSLIST_NODE_ALIGNMENT)
|
||
|
#define TSLIST_HEAD_ALIGN_POST
|
||
|
#define TSLIST_NODE_ALIGN_POST
|
||
|
#elif defined( GNUC )
|
||
|
#define TSLIST_HEAD_ALIGN
|
||
|
#define TSLIST_NODE_ALIGN
|
||
|
#define TSLIST_HEAD_ALIGN_POST DECL_ALIGN(TSLIST_HEAD_ALIGNMENT)
|
||
|
#define TSLIST_NODE_ALIGN_POST DECL_ALIGN(TSLIST_NODE_ALIGNMENT)
|
||
|
#elif defined( _PS3 )
|
||
|
#define TSLIST_HEAD_ALIGNMENT 8
|
||
|
#define TSLIST_NODE_ALIGNMENT 8
|
||
|
|
||
|
#define TSLIST_HEAD_ALIGN ALIGN8
|
||
|
#define TSLIST_NODE_ALIGN ALIGN8
|
||
|
#define TSLIST_HEAD_ALIGN_POST ALIGN8_POST
|
||
|
#define TSLIST_NODE_ALIGN_POST ALIGN8_POST
|
||
|
|
||
|
#else
|
||
|
#error
|
||
|
#endif
|
||
|
|
||
|
PLATFORM_INTERFACE bool RunTSQueueTests(int nListSize = 10000, int nTests = 1);
|
||
|
PLATFORM_INTERFACE bool RunTSListTests(int nListSize = 10000, int nTests = 1);
|
||
|
|
||
|
#ifdef USE_NATIVE_SLIST
|
||
|
typedef SLIST_ENTRY TSLNodeBase_t;
|
||
|
typedef SLIST_HEADER TSLHead_t;
|
||
|
#else
|
||
|
struct TSLIST_NODE_ALIGN TSLNodeBase_t
|
||
|
{
|
||
|
TSLNodeBase_t* Next;
|
||
|
} TSLIST_NODE_ALIGN_POST;
|
||
|
|
||
|
union TSLIST_HEAD_ALIGN TSLHead_t
|
||
|
{
|
||
|
struct Value_t
|
||
|
{
|
||
|
TSLNodeBase_t* Next;
|
||
|
#ifdef VALVE_BIG_ENDIAN
|
||
|
int16 Sequence;
|
||
|
int16 Depth;
|
||
|
#else
|
||
|
int16 Depth;
|
||
|
int16 Sequence;
|
||
|
#endif
|
||
|
#ifdef PLATFORM_64BITS
|
||
|
int32 Padding;
|
||
|
#endif
|
||
|
} value;
|
||
|
|
||
|
struct Value32_t
|
||
|
{
|
||
|
TSLNodeBase_t* Next_do_not_use_me;
|
||
|
int32 DepthAndSequence;
|
||
|
} value32;
|
||
|
|
||
|
#ifdef PLATFORM_64BITS
|
||
|
int128 value64x128;
|
||
|
#else
|
||
|
int64 value64x128;
|
||
|
#endif
|
||
|
} TSLIST_HEAD_ALIGN_POST;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
class CTSListBase
|
||
|
{
|
||
|
public:
|
||
|
|
||
|
static void* operator new(size_t size)
|
||
|
{
|
||
|
CTSListBase* pNode = (CTSListBase*)MemAlloc_AllocAlignedFileLine(size, TSLIST_HEAD_ALIGNMENT, __FILE__, __LINE__);
|
||
|
return pNode;
|
||
|
}
|
||
|
|
||
|
static void* operator new(size_t size, int nBlockUse, const char* pFileName, int nLine)
|
||
|
{
|
||
|
CTSListBase* pNode = (CTSListBase*)MemAlloc_AllocAlignedFileLine(size, TSLIST_HEAD_ALIGNMENT, pFileName, nLine);
|
||
|
return pNode;
|
||
|
}
|
||
|
|
||
|
static void operator delete(void* p)
|
||
|
{
|
||
|
MemAlloc_FreeAligned(p);
|
||
|
}
|
||
|
|
||
|
static void operator delete(void* p, int nBlockUse, const char* pFileName, int nLine)
|
||
|
{
|
||
|
MemAlloc_FreeAligned(p);
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
static void* operator new[](size_t size);
|
||
|
static void operator delete[](void* p);
|
||
|
|
||
|
public:
|
||
|
|
||
|
CTSListBase()
|
||
|
{
|
||
|
if (((size_t)&m_Head) % TSLIST_HEAD_ALIGNMENT != 0)
|
||
|
{
|
||
|
Error("CTSListBase: Misaligned list\n");
|
||
|
DebuggerBreak();
|
||
|
}
|
||
|
|
||
|
#ifdef USE_NATIVE_SLIST
|
||
|
InitializeSListHead(&m_Head);
|
||
|
#elif defined(PLATFORM_64BITS)
|
||
|
m_Head.value64x128 = int128_zero();
|
||
|
#else
|
||
|
m_Head.value64x128 = (int64)0;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
~CTSListBase()
|
||
|
{
|
||
|
Detach();
|
||
|
}
|
||
|
|
||
|
TSLNodeBase_t* Push(TSLNodeBase_t* pNode)
|
||
|
{
|
||
|
#ifdef _DEBUG
|
||
|
if ((size_t)pNode % TSLIST_NODE_ALIGNMENT != 0)
|
||
|
{
|
||
|
Error("CTSListBase: Misaligned node\n");
|
||
|
DebuggerBreak();
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef USE_NATIVE_SLIST
|
||
|
#ifdef _X360
|
||
|
return (TSLNodeBase_t*)InterlockedPushEntrySListRelease(&m_Head, pNode);
|
||
|
#else
|
||
|
return (TSLNodeBase_t*)InterlockedPushEntrySList(&m_Head, pNode);
|
||
|
#endif
|
||
|
#else
|
||
|
TSLHead_t oldHead;
|
||
|
TSLHead_t newHead;
|
||
|
|
||
|
#if defined( PLATFORM_PS3 ) || defined( PLATFORM_X360 )
|
||
|
__lwsync();
|
||
|
#endif
|
||
|
|
||
|
#ifdef PLATFORM_64BITS
|
||
|
newHead.value.Padding = 0;
|
||
|
#endif
|
||
|
for (;; )
|
||
|
{
|
||
|
oldHead.value64x128 = m_Head.value64x128;
|
||
|
pNode->Next = oldHead.value.Next;
|
||
|
newHead.value.Next = pNode;
|
||
|
|
||
|
newHead.value32.DepthAndSequence = oldHead.value32.DepthAndSequence + 0x10001;
|
||
|
|
||
|
|
||
|
if (ThreadInterlockedAssignIf64x128(&m_Head.value64x128, newHead.value64x128, oldHead.value64x128))
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
ThreadPause();
|
||
|
};
|
||
|
|
||
|
return (TSLNodeBase_t*)oldHead.value.Next;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
TSLNodeBase_t* Pop()
|
||
|
{
|
||
|
#ifdef USE_NATIVE_SLIST
|
||
|
#ifdef _X360
|
||
|
TSLNodeBase_t* pNode = (TSLNodeBase_t*)InterlockedPopEntrySListAcquire(&m_Head);
|
||
|
#else
|
||
|
TSLNodeBase_t* pNode = (TSLNodeBase_t*)InterlockedPopEntrySList(&m_Head);
|
||
|
#endif
|
||
|
return pNode;
|
||
|
#else
|
||
|
TSLHead_t oldHead;
|
||
|
TSLHead_t newHead;
|
||
|
|
||
|
#ifdef PLATFORM_64BITS
|
||
|
newHead.value.Padding = 0;
|
||
|
#endif
|
||
|
for (;; )
|
||
|
{
|
||
|
oldHead.value64x128 = m_Head.value64x128;
|
||
|
if (!oldHead.value.Next)
|
||
|
return NULL;
|
||
|
|
||
|
newHead.value.Next = oldHead.value.Next->Next;
|
||
|
newHead.value32.DepthAndSequence = oldHead.value32.DepthAndSequence - 1;
|
||
|
|
||
|
|
||
|
if (ThreadInterlockedAssignIf64x128(&m_Head.value64x128, newHead.value64x128, oldHead.value64x128))
|
||
|
{
|
||
|
#if defined( PLATFORM_PS3 ) || defined( PLATFORM_X360 )
|
||
|
__lwsync();
|
||
|
#endif
|
||
|
break;
|
||
|
}
|
||
|
ThreadPause();
|
||
|
};
|
||
|
|
||
|
return (TSLNodeBase_t*)oldHead.value.Next;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
TSLNodeBase_t* Detach()
|
||
|
{
|
||
|
#ifdef USE_NATIVE_SLIST
|
||
|
TSLNodeBase_t* pBase = (TSLNodeBase_t*)InterlockedFlushSList(&m_Head);
|
||
|
#if defined( _X360 ) || defined( _PS3 )
|
||
|
__lwsync();
|
||
|
#endif
|
||
|
return pBase;
|
||
|
#else
|
||
|
TSLHead_t oldHead;
|
||
|
TSLHead_t newHead;
|
||
|
|
||
|
#ifdef PLATFORM_64BITS
|
||
|
newHead.value.Padding = 0;
|
||
|
#endif
|
||
|
do
|
||
|
{
|
||
|
ThreadPause();
|
||
|
|
||
|
oldHead.value64x128 = m_Head.value64x128;
|
||
|
if (!oldHead.value.Next)
|
||
|
return NULL;
|
||
|
|
||
|
newHead.value.Next = NULL;
|
||
|
newHead.value32.DepthAndSequence = oldHead.value32.DepthAndSequence & 0xffff0000;
|
||
|
|
||
|
} while (!ThreadInterlockedAssignIf64x128(&m_Head.value64x128, newHead.value64x128, oldHead.value64x128));
|
||
|
|
||
|
return (TSLNodeBase_t*)oldHead.value.Next;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
TSLHead_t* AccessUnprotected()
|
||
|
{
|
||
|
return &m_Head;
|
||
|
}
|
||
|
|
||
|
int Count() const
|
||
|
{
|
||
|
#ifdef USE_NATIVE_SLIST
|
||
|
return QueryDepthSList(const_cast<TSLHead_t*>(&m_Head));
|
||
|
#else
|
||
|
return m_Head.value.Depth;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
TSLHead_t m_Head;
|
||
|
} TSLIST_HEAD_ALIGN_POST;
|
||
|
|
||
|
template <typename T>
|
||
|
class TSLIST_HEAD_ALIGN CTSSimpleList : public CTSListBase
|
||
|
{
|
||
|
public:
|
||
|
void Push(T* pNode)
|
||
|
{
|
||
|
Assert(sizeof(T) >= sizeof(TSLNodeBase_t));
|
||
|
CTSListBase::Push((TSLNodeBase_t*)pNode);
|
||
|
}
|
||
|
|
||
|
T* Pop()
|
||
|
{
|
||
|
return (T*)CTSListBase::Pop();
|
||
|
}
|
||
|
} TSLIST_HEAD_ALIGN_POST;
|
||
|
|
||
|
template< class T >
|
||
|
class TSLIST_HEAD_ALIGN CTSPool : public CTSListBase
|
||
|
{
|
||
|
struct TSLIST_NODE_ALIGN simpleTSPoolStruct_t : public TSLNodeBase_t
|
||
|
{
|
||
|
T elem;
|
||
|
} TSLIST_NODE_ALIGN_POST;
|
||
|
|
||
|
public:
|
||
|
|
||
|
~CTSPool()
|
||
|
{
|
||
|
Purge();
|
||
|
}
|
||
|
|
||
|
void Purge()
|
||
|
{
|
||
|
simpleTSPoolStruct_t* pNode = NULL;
|
||
|
while (1)
|
||
|
{
|
||
|
pNode = (simpleTSPoolStruct_t*)CTSListBase::Pop();
|
||
|
if (!pNode)
|
||
|
break;
|
||
|
delete pNode;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void PutObject(T* pInfo)
|
||
|
{
|
||
|
char* pElem = (char*)pInfo;
|
||
|
pElem -= offsetof(simpleTSPoolStruct_t, elem);
|
||
|
simpleTSPoolStruct_t* pNode = (simpleTSPoolStruct_t*)pElem;
|
||
|
|
||
|
CTSListBase::Push(pNode);
|
||
|
}
|
||
|
|
||
|
T* GetObject()
|
||
|
{
|
||
|
simpleTSPoolStruct_t* pNode = (simpleTSPoolStruct_t*)CTSListBase::Pop();
|
||
|
if (!pNode)
|
||
|
{
|
||
|
pNode = new simpleTSPoolStruct_t;
|
||
|
}
|
||
|
return &pNode->elem;
|
||
|
}
|
||
|
|
||
|
FORCEINLINE T* Get()
|
||
|
{
|
||
|
return GetObject();
|
||
|
}
|
||
|
} TSLIST_HEAD_ALIGN_POST;
|
||
|
template <typename T>
|
||
|
class TSLIST_HEAD_ALIGN CTSList : public CTSListBase
|
||
|
{
|
||
|
public:
|
||
|
struct TSLIST_NODE_ALIGN Node_t : public TSLNodeBase_t
|
||
|
{
|
||
|
Node_t() {}
|
||
|
Node_t(const T& init) : elem(init) {}
|
||
|
T elem;
|
||
|
|
||
|
static void* operator new(size_t size)
|
||
|
{
|
||
|
Node_t* pNode = (Node_t*)MemAlloc_AllocAlignedFileLine(size, TSLIST_NODE_ALIGNMENT, __FILE__, __LINE__);
|
||
|
return pNode;
|
||
|
}
|
||
|
|
||
|
static void* operator new(size_t size, int nBlockUse, const char* pFileName, int nLine)
|
||
|
{
|
||
|
Node_t* pNode = (Node_t*)MemAlloc_AllocAlignedFileLine(size, TSLIST_NODE_ALIGNMENT, pFileName, nLine);
|
||
|
return pNode;
|
||
|
}
|
||
|
|
||
|
static void operator delete(void* p)
|
||
|
{
|
||
|
MemAlloc_FreeAligned(p);
|
||
|
}
|
||
|
static void operator delete(void* p, int nBlockUse, const char* pFileName, int nLine)
|
||
|
{
|
||
|
MemAlloc_FreeAligned(p);
|
||
|
}
|
||
|
|
||
|
} TSLIST_NODE_ALIGN_POST;
|
||
|
|
||
|
~CTSList()
|
||
|
{
|
||
|
Purge();
|
||
|
}
|
||
|
|
||
|
void Purge()
|
||
|
{
|
||
|
Node_t* pCurrent = Detach();
|
||
|
Node_t* pNext;
|
||
|
while (pCurrent)
|
||
|
{
|
||
|
pNext = (Node_t*)pCurrent->Next;
|
||
|
delete pCurrent;
|
||
|
pCurrent = pNext;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void RemoveAll()
|
||
|
{
|
||
|
Purge();
|
||
|
}
|
||
|
|
||
|
Node_t* Push(Node_t* pNode)
|
||
|
{
|
||
|
return (Node_t*)CTSListBase::Push(pNode);
|
||
|
}
|
||
|
|
||
|
Node_t* Pop()
|
||
|
{
|
||
|
return (Node_t*)CTSListBase::Pop();
|
||
|
}
|
||
|
|
||
|
void PushItem(const T& init)
|
||
|
{
|
||
|
Push(new Node_t(init));
|
||
|
}
|
||
|
|
||
|
bool PopItem(T* pResult)
|
||
|
{
|
||
|
Node_t* pNode = Pop();
|
||
|
if (!pNode)
|
||
|
return false;
|
||
|
*pResult = pNode->elem;
|
||
|
delete pNode;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
Node_t* Detach()
|
||
|
{
|
||
|
return (Node_t*)CTSListBase::Detach();
|
||
|
}
|
||
|
|
||
|
} TSLIST_HEAD_ALIGN_POST;
|
||
|
|
||
|
template <typename T>
|
||
|
class TSLIST_HEAD_ALIGN CTSListWithFreeList : public CTSListBase
|
||
|
{
|
||
|
public:
|
||
|
struct TSLIST_NODE_ALIGN Node_t : public TSLNodeBase_t
|
||
|
{
|
||
|
Node_t() {}
|
||
|
Node_t(const T& init) : elem(init) {}
|
||
|
|
||
|
T elem;
|
||
|
} TSLIST_NODE_ALIGN_POST;
|
||
|
|
||
|
~CTSListWithFreeList()
|
||
|
{
|
||
|
Purge();
|
||
|
}
|
||
|
|
||
|
void Purge()
|
||
|
{
|
||
|
Node_t* pCurrent = Detach();
|
||
|
Node_t* pNext;
|
||
|
while (pCurrent)
|
||
|
{
|
||
|
pNext = (Node_t*)pCurrent->Next;
|
||
|
delete pCurrent;
|
||
|
pCurrent = pNext;
|
||
|
}
|
||
|
pCurrent = (Node_t*)m_FreeList.Detach();
|
||
|
while (pCurrent)
|
||
|
{
|
||
|
pNext = (Node_t*)pCurrent->Next;
|
||
|
delete pCurrent;
|
||
|
pCurrent = pNext;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void RemoveAll()
|
||
|
{
|
||
|
Node_t* pCurrent = Detach();
|
||
|
Node_t* pNext;
|
||
|
while (pCurrent)
|
||
|
{
|
||
|
pNext = (Node_t*)pCurrent->Next;
|
||
|
m_FreeList.Push(pCurrent);
|
||
|
pCurrent = pNext;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Node_t* Push(Node_t* pNode)
|
||
|
{
|
||
|
return (Node_t*)CTSListBase::Push(pNode);
|
||
|
}
|
||
|
|
||
|
Node_t* Pop()
|
||
|
{
|
||
|
return (Node_t*)CTSListBase::Pop();
|
||
|
}
|
||
|
|
||
|
void PushItem(const T& init)
|
||
|
{
|
||
|
Node_t* pNode = (Node_t*)m_FreeList.Pop();
|
||
|
if (!pNode)
|
||
|
{
|
||
|
pNode = new Node_t;
|
||
|
}
|
||
|
pNode->elem = init;
|
||
|
Push(pNode);
|
||
|
}
|
||
|
|
||
|
bool PopItem(T* pResult)
|
||
|
{
|
||
|
Node_t* pNode = Pop();
|
||
|
if (!pNode)
|
||
|
return false;
|
||
|
*pResult = pNode->elem;
|
||
|
m_FreeList.Push(pNode);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
Node_t* Detach()
|
||
|
{
|
||
|
return (Node_t*)CTSListBase::Detach();
|
||
|
}
|
||
|
|
||
|
void FreeNode(Node_t* pNode)
|
||
|
{
|
||
|
m_FreeList.Push(pNode);
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
CTSListBase m_FreeList;
|
||
|
} TSLIST_HEAD_ALIGN_POST;
|
||
|
|
||
|
template <typename T, bool bTestOptimizer = false>
|
||
|
class TSLIST_HEAD_ALIGN CTSQueue
|
||
|
{
|
||
|
public:
|
||
|
|
||
|
static void* operator new(size_t size)
|
||
|
{
|
||
|
CTSQueue* pNode = (CTSQueue*)MemAlloc_AllocAlignedFileLine(size, TSLIST_HEAD_ALIGNMENT, __FILE__, __LINE__);
|
||
|
return pNode;
|
||
|
}
|
||
|
|
||
|
static void* operator new(size_t size, int nBlockUse, const char* pFileName, int nLine)
|
||
|
{
|
||
|
CTSQueue* pNode = (CTSQueue*)MemAlloc_AllocAlignedFileLine(size, TSLIST_HEAD_ALIGNMENT, pFileName, nLine);
|
||
|
return pNode;
|
||
|
}
|
||
|
|
||
|
static void operator delete(void* p)
|
||
|
{
|
||
|
MemAlloc_FreeAligned(p);
|
||
|
}
|
||
|
|
||
|
static void operator delete(void* p, int nBlockUse, const char* pFileName, int nLine)
|
||
|
{
|
||
|
MemAlloc_FreeAligned(p);
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
static void* operator new[](size_t size) throw()
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
static void operator delete [](void* p)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
public:
|
||
|
|
||
|
struct TSLIST_NODE_ALIGN Node_t
|
||
|
{
|
||
|
static void* operator new(size_t size)
|
||
|
{
|
||
|
Node_t* pNode = (Node_t*)MemAlloc_AllocAlignedFileLine(size, TSLIST_HEAD_ALIGNMENT, __FILE__, __LINE__);
|
||
|
return pNode;
|
||
|
}
|
||
|
|
||
|
static void* operator new(size_t size, int nBlockUse, const char* pFileName, int nLine)
|
||
|
{
|
||
|
Node_t* pNode = (Node_t*)MemAlloc_AllocAlignedFileLine(size, TSLIST_HEAD_ALIGNMENT, pFileName, nLine);
|
||
|
return pNode;
|
||
|
}
|
||
|
|
||
|
static void operator delete(void* p)
|
||
|
{
|
||
|
MemAlloc_FreeAligned(p);
|
||
|
}
|
||
|
|
||
|
static void operator delete(void* p, int nBlockUse, const char* pFileName, int nLine)
|
||
|
{
|
||
|
MemAlloc_FreeAligned(p);
|
||
|
}
|
||
|
|
||
|
Node_t() {}
|
||
|
Node_t(const T& init) : elem(init) {}
|
||
|
|
||
|
Node_t* pNext;
|
||
|
T elem;
|
||
|
} TSLIST_NODE_ALIGN_POST;
|
||
|
|
||
|
union TSLIST_HEAD_ALIGN NodeLink_t
|
||
|
{
|
||
|
static void* operator new(size_t size)
|
||
|
{
|
||
|
NodeLink_t* pNode = (NodeLink_t*)MemAlloc_AllocAlignedFileLine(size, TSLIST_HEAD_ALIGNMENT, __FILE__, __LINE__);
|
||
|
return pNode;
|
||
|
}
|
||
|
|
||
|
static void operator delete(void* p)
|
||
|
{
|
||
|
MemAlloc_FreeAligned(p);
|
||
|
}
|
||
|
|
||
|
struct Value_t
|
||
|
{
|
||
|
Node_t* pNode;
|
||
|
intp sequence;
|
||
|
} value;
|
||
|
|
||
|
#ifdef PLATFORM_64BITS
|
||
|
int128 value64x128;
|
||
|
#else
|
||
|
int64 value64x128;
|
||
|
#endif
|
||
|
} TSLIST_HEAD_ALIGN_POST;
|
||
|
|
||
|
CTSQueue()
|
||
|
{
|
||
|
COMPILE_TIME_ASSERT(sizeof(Node_t) >= sizeof(TSLNodeBase_t));
|
||
|
if (((size_t)&m_Head) % TSLIST_HEAD_ALIGNMENT != 0)
|
||
|
{
|
||
|
Error("CTSQueue: Misaligned queue\n");
|
||
|
DebuggerBreak();
|
||
|
}
|
||
|
if (((size_t)&m_Tail) % TSLIST_HEAD_ALIGNMENT != 0)
|
||
|
{
|
||
|
Error("CTSQueue: Misaligned queue\n");
|
||
|
DebuggerBreak();
|
||
|
}
|
||
|
m_Count = 0;
|
||
|
m_Head.value.sequence = m_Tail.value.sequence = 0;
|
||
|
m_Head.value.pNode = m_Tail.value.pNode = new Node_t;
|
||
|
m_Head.value.pNode->pNext = End();
|
||
|
}
|
||
|
|
||
|
~CTSQueue()
|
||
|
{
|
||
|
Purge();
|
||
|
Assert(m_Count == 0);
|
||
|
Assert(m_Head.value.pNode == m_Tail.value.pNode);
|
||
|
Assert(m_Head.value.pNode->pNext == End());
|
||
|
delete m_Head.value.pNode;
|
||
|
}
|
||
|
|
||
|
void Purge()
|
||
|
{
|
||
|
if (IsDebug())
|
||
|
{
|
||
|
ValidateQueue();
|
||
|
}
|
||
|
|
||
|
Node_t* pNode;
|
||
|
while ((pNode = Pop()) != NULL)
|
||
|
{
|
||
|
delete pNode;
|
||
|
}
|
||
|
|
||
|
while ((pNode = (Node_t*)m_FreeNodes.Pop()) != NULL)
|
||
|
{
|
||
|
delete pNode;
|
||
|
}
|
||
|
|
||
|
Assert(m_Count == 0);
|
||
|
Assert(m_Head.value.pNode == m_Tail.value.pNode);
|
||
|
Assert(m_Head.value.pNode->pNext == End());
|
||
|
|
||
|
m_Head.value.sequence = m_Tail.value.sequence = 0;
|
||
|
}
|
||
|
|
||
|
void RemoveAll()
|
||
|
{
|
||
|
if (IsDebug())
|
||
|
{
|
||
|
ValidateQueue();
|
||
|
}
|
||
|
|
||
|
Node_t* pNode;
|
||
|
while ((pNode = Pop()) != NULL)
|
||
|
{
|
||
|
m_FreeNodes.Push((TSLNodeBase_t*)pNode);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool ValidateQueue()
|
||
|
{
|
||
|
if (IsDebug())
|
||
|
{
|
||
|
bool bResult = true;
|
||
|
int nNodes = 0;
|
||
|
if (m_Tail.value.pNode->pNext != End())
|
||
|
{
|
||
|
DebuggerBreakIfDebugging();
|
||
|
bResult = false;
|
||
|
}
|
||
|
|
||
|
if (m_Count == 0)
|
||
|
{
|
||
|
if (m_Head.value.pNode != m_Tail.value.pNode)
|
||
|
{
|
||
|
DebuggerBreakIfDebugging();
|
||
|
bResult = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Node_t* pNode = m_Head.value.pNode;
|
||
|
while (pNode != End())
|
||
|
{
|
||
|
nNodes++;
|
||
|
pNode = pNode->pNext;
|
||
|
}
|
||
|
|
||
|
nNodes--;
|
||
|
|
||
|
if (nNodes != m_Count)
|
||
|
{
|
||
|
DebuggerBreakIfDebugging();
|
||
|
bResult = false;
|
||
|
}
|
||
|
|
||
|
if (!bResult)
|
||
|
{
|
||
|
Msg("Corrupt CTSQueueDetected");
|
||
|
}
|
||
|
|
||
|
return bResult;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void FinishPush(Node_t* pNode, const NodeLink_t& oldTail)
|
||
|
{
|
||
|
NodeLink_t newTail;
|
||
|
|
||
|
newTail.value.pNode = pNode;
|
||
|
newTail.value.sequence = oldTail.value.sequence + 1;
|
||
|
|
||
|
ThreadMemoryBarrier();
|
||
|
|
||
|
InterlockedCompareExchangeNodeLink(&m_Tail, newTail, oldTail);
|
||
|
}
|
||
|
|
||
|
Node_t* Push(Node_t* pNode)
|
||
|
{
|
||
|
#ifdef _DEBUG
|
||
|
if ((size_t)pNode % TSLIST_NODE_ALIGNMENT != 0)
|
||
|
{
|
||
|
Error("CTSListBase: Misaligned node\n");
|
||
|
DebuggerBreak();
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
NodeLink_t oldTail;
|
||
|
|
||
|
pNode->pNext = End();
|
||
|
|
||
|
for (;; )
|
||
|
{
|
||
|
oldTail.value.sequence = m_Tail.value.sequence;
|
||
|
oldTail.value.pNode = m_Tail.value.pNode;
|
||
|
if (InterlockedCompareExchangeNode(&(oldTail.value.pNode->pNext), pNode, End()) == End())
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
FinishPush(oldTail.value.pNode->pNext, oldTail);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
FinishPush(pNode, oldTail);
|
||
|
|
||
|
m_Count++;
|
||
|
|
||
|
return oldTail.value.pNode;
|
||
|
}
|
||
|
|
||
|
Node_t* Pop()
|
||
|
{
|
||
|
#define TSQUEUE_BAD_NODE_LINK ( (Node_t *)INT_TO_POINTER( 0xdeadbeef ) )
|
||
|
NodeLink_t* volatile pHead = &m_Head;
|
||
|
NodeLink_t* volatile pTail = &m_Tail;
|
||
|
Node_t* volatile* pHeadNode = &m_Head.value.pNode;
|
||
|
volatile intp* volatile pHeadSequence = &m_Head.value.sequence;
|
||
|
Node_t* volatile* pTailNode = &pTail->value.pNode;
|
||
|
|
||
|
NodeLink_t head;
|
||
|
NodeLink_t newHead;
|
||
|
Node_t* pNext;
|
||
|
intp tailSequence;
|
||
|
T elem;
|
||
|
|
||
|
for (;; )
|
||
|
{
|
||
|
head.value.sequence = *pHeadSequence;
|
||
|
ThreadMemoryBarrier();
|
||
|
head.value.pNode = *pHeadNode;
|
||
|
tailSequence = pTail->value.sequence;
|
||
|
pNext = head.value.pNode->pNext;
|
||
|
|
||
|
if (!pNext || head.value.sequence != *pHeadSequence)
|
||
|
continue;
|
||
|
|
||
|
if (bTestOptimizer)
|
||
|
{
|
||
|
if (pNext == TSQUEUE_BAD_NODE_LINK)
|
||
|
{
|
||
|
Msg("Bad node link detected\n");
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (head.value.pNode == *pTailNode)
|
||
|
{
|
||
|
if (pNext == End())
|
||
|
return NULL;
|
||
|
|
||
|
NodeLink_t& oldTail = head;
|
||
|
oldTail.value.sequence = tailSequence;
|
||
|
FinishPush(pNext, oldTail);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (pNext != End())
|
||
|
{
|
||
|
elem = pNext->elem;
|
||
|
newHead.value.pNode = pNext;
|
||
|
newHead.value.sequence = head.value.sequence + 1;
|
||
|
if (InterlockedCompareExchangeNodeLink(pHead, newHead, head))
|
||
|
{
|
||
|
ThreadMemoryBarrier();
|
||
|
if (bTestOptimizer)
|
||
|
{
|
||
|
head.value.pNode->pNext = TSQUEUE_BAD_NODE_LINK;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
m_Count--;
|
||
|
head.value.pNode->elem = elem;
|
||
|
return head.value.pNode;
|
||
|
}
|
||
|
|
||
|
void FreeNode(Node_t* pNode)
|
||
|
{
|
||
|
m_FreeNodes.Push((TSLNodeBase_t*)pNode);
|
||
|
}
|
||
|
|
||
|
void PushItem(const T& init)
|
||
|
{
|
||
|
Node_t* pNode = (Node_t*)m_FreeNodes.Pop();
|
||
|
if (pNode)
|
||
|
{
|
||
|
pNode->elem = init;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pNode = new Node_t(init);
|
||
|
}
|
||
|
Push(pNode);
|
||
|
}
|
||
|
|
||
|
bool PopItem(T* pResult)
|
||
|
{
|
||
|
Node_t* pNode = Pop();
|
||
|
if (!pNode)
|
||
|
return false;
|
||
|
|
||
|
*pResult = pNode->elem;
|
||
|
m_FreeNodes.Push((TSLNodeBase_t*)pNode);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
int Count() const
|
||
|
{
|
||
|
return m_Count;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
Node_t* End() { return (Node_t*)this; }
|
||
|
|
||
|
Node_t* InterlockedCompareExchangeNode(Node_t* volatile* ppNode, Node_t* value, Node_t* comperand)
|
||
|
{
|
||
|
return (Node_t*)::ThreadInterlockedCompareExchangePointer((void**)ppNode, value, comperand);
|
||
|
}
|
||
|
|
||
|
bool InterlockedCompareExchangeNodeLink(NodeLink_t volatile* pLink, const NodeLink_t& value, const NodeLink_t& comperand)
|
||
|
{
|
||
|
return ThreadInterlockedAssignIf64x128(&pLink->value64x128, value.value64x128, comperand.value64x128);
|
||
|
}
|
||
|
|
||
|
NodeLink_t m_Head;
|
||
|
NodeLink_t m_Tail;
|
||
|
|
||
|
CInterlockedInt m_Count;
|
||
|
|
||
|
CTSListBase m_FreeNodes;
|
||
|
} TSLIST_NODE_ALIGN_POST;
|
||
|
|
||
|
#if defined( _WIN32 )
|
||
|
#pragma warning( pop )
|
||
|
#endif
|
||
|
|
||
|
#endif
|