windows-nt/Source/XPSP1/NT/net/upnp/host/upnphost/inc/svsutil.hxx

2056 lines
53 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1998 Microsoft Corporation
Module Name:
svsutil.hxx
Abstract:
Miscellaneous useful utilities header
Author:
Sergey Solyanik (SergeyS)
--*/
#if ! defined (__svsutil_HXX__)
#define __svsutil_HXX__ 1
#include <tchar.h>
#if ! defined (UNDER_CE)
#include <wchar.h>
#include <stddef.h>
#endif
#if ! defined (TRUE)
#define TRUE (1==1)
#endif
#if ! defined (FALSE)
#define FALSE (1==2)
#endif
#if defined (_DEBUG) || defined (DEBUG)
#define SVSUTIL_DEBUG_ANY 1
#define SVSUTIL_DEBUG_TREE 1
#define SVSUTIL_DEBUG_QUEUE 1
#define SVSUTIL_DEBUG_STACK 1
#define SVSUTIL_DEBUG_HEAP 1
#define SVSUTIL_DEBUG_ARRAYS 1
#define SVSUTIL_DEBUG_MT 1
#define SVSUTIL_DEBUG_THREADS 1
#endif
#if defined (SVSUTIL_DEBUG_ANY)
#define SVSUTIL_ASSERT(c) ((c)? TRUE : (svsutil_AssertBroken (TEXT(__FILE__), __LINE__), TRUE))
#else
#define SVSUTIL_ASSERT(c)
#endif
#define SVSUTIL_MAX_ALIGNMENT 8
#define SVSUTIL_COLOR_BLACK 0
#define SVSUTIL_COLOR_RED 1
#define SVSUTIL_TREE_INITIAL 20
#define SVSUTIL_QUEUE_INITIAL 20
#define SVSUTIL_STACK_INITIAL 20
#define SVSUTIL_ATIMER_INCR 10
#if defined (SVSUTIL_DEBUG_ARRAYS)
#define SVSUTIL_TIER_COLLECTION_BIT 2
#define SVSUTIL_TIER_ELEMENT_BIT 3
#else
#define SVSUTIL_TIER_COLLECTION_BIT 6
#define SVSUTIL_TIER_ELEMENT_BIT 5
#endif
#define SVSUTIL_TIER_COLLECTION_SIZE (1 << SVSUTIL_TIER_COLLECTION_BIT)
#define SVSUTIL_TIER_ELEMENT_SIZE (1 << SVSUTIL_TIER_ELEMENT_BIT)
#define SVSUTIL_TIER_COLLECTION_MASK ((~((-1) << SVSUTIL_TIER_COLLECTION_BIT)) << SVSUTIL_TIER_ELEMENT_BIT)
#define SVSUTIL_TIER_ELEMENT_MASK (~((-1) << SVSUTIL_TIER_ELEMENT_BIT))
#define SVSUTIL_TIER_MASK (SVSUTIL_TIER_COLLECTION_MASK | SVSUTIL_TIER_ELEMENT_MASK)
#define SVSUTIL_TIER_BIT (SVSUTIL_TIER_COLLECTION_BIT + SVSUTIL_TIER_ELEMENT_BIT)
#define SVSUTIL_ARRLEN(array) (sizeof(array)/sizeof(array[0]))
#define SVSUTIL_CONSTSTRLEN(string) (SVSUTIL_ARRLEN((string)) - 1) // Do not count trailing '\0'
#define SVSUTIL_HANDLE_INVALID 0
//
// General typedefs
//
struct FixedMemDescr;
struct HashDatabase;
struct SVSTimer;
struct SVSAttrTimer;
#define MAXSKEY ((SVSCKey)-1)
#define SORTINV(kKey) (MAXSKEY - kKey)
typedef unsigned long SVSCKey; // Comparison key - this HAS to be unsigned!
typedef unsigned long SVSHKey; // Hash key
typedef unsigned long SVSHandle; // Handle
typedef void *(*FuncAlloc)(int iSize, void *pvPrivateData);
typedef void (*FuncFree)(void *pvPtr, void *pvPrivateData);
typedef int (*FuncDebugOut)(void *pvPtr, TCHAR *lpszFormat, ...);
#if defined (__cplusplus)
extern "C" {
#endif
//
// Externs
//
extern FuncAlloc g_funcAlloc;
extern FuncFree g_funcFree;
extern FuncDebugOut g_funcDebugOut;
extern void *g_pvAllocData;
extern void *g_pvFreeData;
extern void *g_pvDebugData;
//
// Prototypes and classes
//
void svsutil_Initialize (void);
void *svsutil_Alloc (int iSize, void *pvData);
void svsutil_Free (void *pvPtr, void *pvData);
unsigned int svsutil_TotalAlloc (void);
int svsutil_AssertBroken (TCHAR *lpszFile, int iLine);
void svsutil_SetAlloc (FuncAlloc a_funcAlloc, FuncFree a_funcFree);
void svsutil_SetAllocData (void *a_pvAllocData, void *a_pvFreeData);
void svsutil_SetDebugOut (FuncDebugOut a_funcDebugOut, void *a_pvDebugData);
wchar_t *svsutil_wcsdup (wchar_t *);
char *svsutil_strdup (char *);
#if defined (UNICODE)
#define svsutil_tcsdup svsutil_wcsdup
#else
#define svsutil_tcsdup svsutil_strdup
#endif
struct FixedMemDescr *svsutil_AllocFixedMemDescr (unsigned int a_uiBlockSize, unsigned int a_uiBlockIncr);
void *svsutil_GetFixed (struct FixedMemDescr *a_pfmd);
void svsutil_FreeFixed (void *pvData, struct FixedMemDescr *a_pfmd);
void svsutil_ReleaseFixedEmpty (struct FixedMemDescr *a_pfmd);
void svsutil_ReleaseFixedNonEmpty (struct FixedMemDescr *a_pfmd);
void svsutil_CompactFixed (struct FixedMemDescr *a_pfmd);
int svsutil_IsFixedEmpty (struct FixedMemDescr *a_pfmd);
int svsutil_FixedBlockSize (struct FixedMemDescr *a_pfmd);
#if defined (_WINDOWS_) || defined (_WINDOWS_CE_)
struct FixedMemDescr *svsutil_AllocFixedMemDescrSynch (unsigned int a_uiBlockSize, unsigned int a_uiBlockIncr, CRITICAL_SECTION *a_pcs);
#endif
struct HashDatabase *svsutil_GetStringHash (int iBuckets, int iSens);
TCHAR *svsutil_StringHashAlloc(struct HashDatabase *pdb, TCHAR *lpszString);
TCHAR *svsutil_StringHashCheck (struct HashDatabase *pdb, TCHAR *lpszString);
int svsutil_StringHashFree (struct HashDatabase *pdb, TCHAR *lpszString);
int svsutil_StringHashRef (struct HashDatabase *pdb, TCHAR *lpszString);
void svsutil_DestroyStringHash (struct HashDatabase *pdb);
#if defined (SVSUTIL_DEBUG_HEAP)
#define svsutil_ReleaseFixed svsutil_ReleaseFixedEmpty
#else
#define svsutil_ReleaseFixed svsutil_ReleaseFixedNonEmpty
#endif
void svsutil_GetAbsTime (unsigned int *ps, unsigned int *pms);
struct SVSAttrTimer *svsutil_AllocAttrTimer (void);
int svsutil_SetAttrTimer (struct SVSAttrTimer *pTimer, SVSHandle hEvent, unsigned int uiAbsTimeMillis);
int svsutil_ClearAttrTimer (struct SVSAttrTimer *pTimer, SVSHandle hEvent);
void svsutil_FreeAttrTimer (struct SVSAttrTimer *pTimer);
void svsutil_WalkAttrTimer (struct SVSAttrTimer *pTimer, void (*pfunc)(unsigned int uiWhen, SVSHandle hEvent, void *pvArg), void *pvArg);
#if defined (__cplusplus)
};
#endif
#if defined (__cplusplus)
#pragma warning(disable:4505)
#if defined (_WINDOWS_) || defined (_WINDOWS_CE_) || defined (UNDER_CE)
class SVSLocalCriticalSection {
CRITICAL_SECTION *m_pcs;
public:
SVSLocalCriticalSection (CRITICAL_SECTION *pcs) {
m_pcs = pcs;
EnterCriticalSection (pcs);
}
~SVSLocalCriticalSection (void) {
LeaveCriticalSection (m_pcs);
}
};
class SVSLocalCriticalSectionX {
CRITICAL_SECTION *m_pcs;
public:
SVSLocalCriticalSectionX (CRITICAL_SECTION *pcs) {
m_pcs = pcs;
if (m_pcs)
EnterCriticalSection (m_pcs);
}
~SVSLocalCriticalSectionX (void) {
if (m_pcs)
LeaveCriticalSection (m_pcs);
}
};
class SVSSynch {
protected:
CRITICAL_SECTION cs;
#if defined (SVSUTIL_DEBUG_MT)
int iRef;
DWORD dwLockingThreadId;
#endif
protected:
SVSSynch (void) {
InitializeCriticalSection (&cs);
#if defined (SVSUTIL_DEBUG_MT)
iRef = 0;
dwLockingThreadId = 0;
#endif
}
~SVSSynch (void) {
#if defined (SVSUTIL_DEBUG_MT)
SVSUTIL_ASSERT ((iRef == 0) && (dwLockingThreadId == 0));
#endif
DeleteCriticalSection (&cs);
}
public:
void Lock (void) {
EnterCriticalSection (&cs);
#if defined (SVSUTIL_DEBUG_MT)
DWORD dwCurrentThreadId = GetCurrentThreadId();
SVSUTIL_ASSERT (((iRef == 0) && (dwLockingThreadId == 0)) || ((iRef > 0) && (dwLockingThreadId == dwCurrentThreadId)));
dwLockingThreadId = dwCurrentThreadId;
iRef++;
#endif
}
void Unlock (void) {
#if defined (SVSUTIL_DEBUG_MT)
DWORD dwCurrentThreadId = GetCurrentThreadId ();
SVSUTIL_ASSERT ((iRef > 0) && (dwLockingThreadId == dwCurrentThreadId));
if (--iRef == 0)
dwLockingThreadId = 0;
#endif
LeaveCriticalSection (&cs);
}
int IsLocked (void) {
#if defined (SVSUTIL_DEBUG_MT)
DWORD dwCurrentThreadId = GetCurrentThreadId();
return (iRef > 0) && (dwLockingThreadId == dwCurrentThreadId);
#else
return TRUE;
#endif
}
};
#endif
class SVSAllocClass {
public:
void *operator new (size_t iSize) {
void *pRes = g_funcAlloc(iSize, g_pvAllocData);
SVSUTIL_ASSERT (pRes);
return pRes;
}
void operator delete(void *ptr) {
g_funcFree (ptr, g_pvFreeData);
}
};
class SVSRefObj {
protected:
int iRef;
public:
void AddRef (void) {
#if defined (_WINDOWS_) || defined (_WINDOWS_CE_)
InterlockedIncrement ((long *)&iRef);
#else
++iRef;
#endif
}
void DelRef (void) {
SVSUTIL_ASSERT (iRef > 0);
#if defined (_WINDOWS_) || defined (_WINDOWS_CE_)
InterlockedDecrement ((long *)&iRef);
#else
--iRef;
#endif
}
int GetRefCount (void) {
return iRef;
}
SVSRefObj (void) {
iRef = 1;
}
};
class SVSSignallingRefObj : public SVSRefObj {
protected:
void (*pfSignal)(void *);
void *pvData;
public:
void DelRef (void) {
SVSUTIL_ASSERT (iRef > 0);
#if defined (_WINDOWS_) || defined (_WINDOWS_CE_)
InterlockedDecrement ((long *)&iRef);
#else
--iRef;
#endif
if ((iRef == 0) && pfSignal)
pfSignal (pvData);
}
SVSSignallingRefObj (void) {
pfSignal = NULL;
pvData = NULL;
}
void SetSignal (void (*a_pfSignal)(void *), void *a_pvData) {
SVSUTIL_ASSERT (pfSignal == NULL);
SVSUTIL_ASSERT (pvData == NULL);
pfSignal = a_pfSignal;
pvData = a_pvData;
}
};
//
// Enumerable class
//
class SVSEnumClass {
public:
virtual SVSHandle EnumStart (void) = 0;
virtual SVSHandle EnumNext (SVSHandle hEnum) = 0;
virtual void *EnumGetData (SVSHandle hEnum) = 0;
virtual SVSCKey EnumGetKey (SVSHandle hEnum) = 0;
};
//
// Queue class
//
class SVSLinkedSegment {
protected:
class SVSLinkedSegment *plsNext;
class SVSLinkedSegment *plsPrev;
void *pvArray[1];
friend class SVSQueue;
friend class SVSStack;
};
class SVSQueue : public SVSAllocClass {
protected:
SVSLinkedSegment *plsHead;
SVSLinkedSegment *plsTail;
unsigned int iSegSize;
unsigned int iBlockSize;
unsigned int iHeadNdx;
unsigned int iTailNdx;
#if defined (SVSUTIL_DEBUG_QUEUE)
void CoherencyCheck (void) {
SVSUTIL_ASSERT(iSegSize > 0);
SVSUTIL_ASSERT(iBlockSize > 0);
SVSUTIL_ASSERT(iHeadNdx < iSegSize);
SVSUTIL_ASSERT(iTailNdx < iSegSize);
SVSUTIL_ASSERT (plsHead->plsNext->plsPrev == plsHead);
SVSUTIL_ASSERT (plsTail->plsNext->plsPrev == plsTail);
SVSUTIL_ASSERT (plsHead->plsPrev->plsNext == plsHead);
SVSUTIL_ASSERT (plsTail->plsPrev->plsNext == plsTail);
}
#endif
public:
SVSQueue (unsigned int a_iSegSize = SVSUTIL_QUEUE_INITIAL) {
SVSUTIL_ASSERT (a_iSegSize > 0);
iSegSize = a_iSegSize;
iHeadNdx = 0;
iTailNdx = 0;
iBlockSize = offsetof (SVSLinkedSegment, pvArray) + a_iSegSize * sizeof(void *);
plsHead = plsTail = (SVSLinkedSegment *)g_funcAlloc(iBlockSize, g_pvAllocData);
SVSUTIL_ASSERT (plsHead);
plsHead->plsPrev = plsHead->plsNext = plsHead;
#if defined (SVSUTIL_DEBUG_QUEUE)
CoherencyCheck ();
#endif
}
~SVSQueue (void) {
SVSLinkedSegment *pls = plsHead->plsNext;
while (pls != plsHead) {
SVSLinkedSegment *plsNext = pls->plsNext;
g_funcFree (pls, g_pvFreeData);
pls = plsNext;
}
g_funcFree (plsHead, g_pvFreeData);
}
int IsEmpty (void) {
#if defined (SVSUTIL_DEBUG_QUEUE)
CoherencyCheck ();
#endif
return (plsHead == plsTail) && (iHeadNdx == iTailNdx);
}
int Put (void *pvData) {
#if defined (SVSUTIL_DEBUG_QUEUE)
CoherencyCheck ();
#endif
plsHead->pvArray[iHeadNdx++] = pvData;
if (iHeadNdx < iSegSize)
return TRUE;
iHeadNdx = 0;
if (plsHead->plsNext != plsTail) {
plsHead = plsHead->plsNext;
return TRUE;
}
SVSLinkedSegment *pls = (SVSLinkedSegment *)g_funcAlloc(iBlockSize, g_pvAllocData);
if (! pls) {
SVSUTIL_ASSERT (0);
iHeadNdx = iSegSize - 1;
return FALSE;
}
pls->plsPrev = plsHead;
pls->plsNext = plsTail;
plsHead->plsNext = pls;
plsTail->plsPrev = pls;
plsHead = pls;
return TRUE;
}
void *Peek (void) {
if (IsEmpty()) {
SVSUTIL_ASSERT(0);
return NULL;
}
return plsTail->pvArray[iTailNdx];
}
void *Get (void) {
if (IsEmpty()) {
SVSUTIL_ASSERT(0);
return NULL;
}
void *pvData = plsTail->pvArray[iTailNdx++];
if (iTailNdx < iSegSize)
return pvData;
iTailNdx = 0;
plsTail = plsTail->plsNext;
return pvData;
}
void Compact (void) {
#if defined (SVSUTIL_DEBUG_QUEUE)
CoherencyCheck ();
#endif
SVSLinkedSegment *pls = plsHead->plsNext;
while (pls != plsTail) {
SVSLinkedSegment *plsNext = pls->plsNext;
g_funcFree (pls, g_pvFreeData);
pls = plsNext;
}
plsHead->plsNext = plsTail;
plsTail->plsPrev = plsHead;
#if defined (SVSUTIL_DEBUG_QUEUE)
CoherencyCheck ();
#endif
}
};
class SVSStack : public SVSAllocClass {
protected:
SVSLinkedSegment *plsBase;
SVSLinkedSegment *plsHead;
unsigned int iSegSize;
unsigned int iBlockSize;
unsigned int iHeadNdx;
#if defined (SVSUTIL_DEBUG_STACK)
void CoherencyCheck (void) {
SVSUTIL_ASSERT (iSegSize > 0);
SVSUTIL_ASSERT (iBlockSize > 0);
SVSUTIL_ASSERT (iHeadNdx < iSegSize);
SVSUTIL_ASSERT (plsBase->plsPrev == NULL);
SVSUTIL_ASSERT ((plsHead == plsBase) || (plsHead->plsPrev->plsNext == plsHead));
SVSUTIL_ASSERT ((! plsHead->plsNext) || (plsHead->plsNext->plsPrev == plsHead));
SVSUTIL_ASSERT ((! plsBase->plsNext) || (plsBase->plsNext->plsPrev == plsBase));
}
#endif
public:
SVSStack (unsigned int a_iSegSize = SVSUTIL_STACK_INITIAL) {
SVSUTIL_ASSERT (a_iSegSize > 0);
iSegSize = a_iSegSize;
iHeadNdx = 0;
iBlockSize = offsetof (SVSLinkedSegment, pvArray) + a_iSegSize * sizeof(void *);
plsHead = plsBase = (SVSLinkedSegment *)g_funcAlloc(iBlockSize, g_pvAllocData);
SVSUTIL_ASSERT (plsHead);
plsHead->plsPrev = plsHead->plsNext = NULL;
#if defined (SVSUTIL_DEBUG_STACK)
CoherencyCheck ();
#endif
}
~SVSStack (void) {
SVSLinkedSegment *pls = plsBase;
while (pls) {
SVSLinkedSegment *plsNext = pls->plsNext;
g_funcFree (pls, g_pvFreeData);
pls = plsNext;
}
}
int IsEmpty (void) {
#if defined (SVSUTIL_DEBUG_STACK)
CoherencyCheck ();
#endif
return (plsHead == plsBase) && (iHeadNdx == 0);
}
int Push (void *pvData) {
#if defined (SVSUTIL_DEBUG_STACK)
CoherencyCheck ();
#endif
plsHead->pvArray[iHeadNdx++] = pvData;
if (iHeadNdx < iSegSize)
return TRUE;
iHeadNdx = 0;
if (plsHead->plsNext != NULL) {
plsHead = plsHead->plsNext;
return TRUE;
}
SVSLinkedSegment *pls = (SVSLinkedSegment *)g_funcAlloc(iBlockSize, g_pvAllocData);
if (! pls) {
SVSUTIL_ASSERT (0);
iHeadNdx = iSegSize - 1;
return FALSE;
}
pls->plsPrev = plsHead;
pls->plsNext = NULL;
plsHead->plsNext = pls;
plsHead = pls;
return TRUE;
}
void *Peek (void) {
if (IsEmpty()) {
SVSUTIL_ASSERT(0);
return NULL;
}
int iHeadNdx2 = (int)iHeadNdx - 1;
SVSLinkedSegment *plsHead2 = plsHead;
if (iHeadNdx2 < 0) {
iHeadNdx2 = iSegSize - 1;
plsHead2 = plsHead->plsPrev;
}
return plsHead2->pvArray[iHeadNdx2];
}
void *Pop (void) {
if (IsEmpty()) {
SVSUTIL_ASSERT(0);
return NULL;
}
if (((int)--iHeadNdx) < 0) {
iHeadNdx = iSegSize - 1;
plsHead = plsHead->plsPrev;
}
return plsHead->pvArray[iHeadNdx];
}
void Compact (void) {
#if defined (SVSUTIL_DEBUG_STACK)
CoherencyCheck ();
#endif
SVSLinkedSegment *pls = plsHead->plsNext;
while (pls) {
SVSLinkedSegment *plsNext = pls->plsNext;
g_funcFree (pls, g_pvFreeData);
pls = plsNext;
}
plsHead->plsNext = NULL;
#if defined (SVSUTIL_DEBUG_STACK)
CoherencyCheck ();
#endif
}
};
//
// Expandable Arrays
//
template <class T> class SVSMTABlock : public SVSAllocClass {
public:
T **m_p_ptCollection;
int m_iNdxFirst;
int m_iNdxLast;
SVSMTABlock *m_pNextBlock;
SVSMTABlock (SVSMTABlock *a_pCurrentHead, int iStartNdx) {
SVSUTIL_ASSERT ((iStartNdx & SVSUTIL_TIER_MASK) == 0);
SVSUTIL_ASSERT (iStartNdx >= 0);
m_pNextBlock = a_pCurrentHead;
m_iNdxFirst = iStartNdx;
m_iNdxLast = iStartNdx | SVSUTIL_TIER_MASK;
m_p_ptCollection = NULL;
}
~SVSMTABlock (void) {
if (! m_p_ptCollection)
return;
for (int i = 0 ; i < SVSUTIL_TIER_COLLECTION_SIZE ; ++i) {
if (! m_p_ptCollection[i])
break;
g_funcFree (m_p_ptCollection[i], g_pvFreeData);
}
g_funcFree (m_p_ptCollection, g_pvFreeData);
}
int AllocateBlock (void) {
SVSUTIL_ASSERT (m_p_ptCollection == NULL);
int iSz = sizeof(T *) * SVSUTIL_TIER_COLLECTION_SIZE;
m_p_ptCollection = (T **)g_funcAlloc (iSz, g_pvAllocData);
if (! m_p_ptCollection) {
SVSUTIL_ASSERT (0);
return FALSE;
}
memset (m_p_ptCollection, 0, iSz);
return TRUE;
}
int AllocateCluster (int i) {
SVSUTIL_ASSERT (m_p_ptCollection[i] == NULL);
m_p_ptCollection[i] = (T *)g_funcAlloc(sizeof(T) * SVSUTIL_TIER_ELEMENT_SIZE, g_pvAllocData);
return m_p_ptCollection[i] != NULL;
}
};
template <class T> class SVSExpArray : public SVSAllocClass {
protected:
int m_iBigBlocks;
int m_iPhysInLast;
SVSMTABlock<T> *m_pFirstBlock;
public:
SVSExpArray(void) {
m_pFirstBlock = NULL;
m_iBigBlocks = 0;
m_iPhysInLast = 0;
}
int SRealloc (int a_iElemNum);
int CRealloc (int a_iElemNum);
~SVSExpArray(void) {
while (m_pFirstBlock) {
SVSMTABlock<T> *pNextBlock = m_pFirstBlock->m_pNextBlock;
delete m_pFirstBlock;
m_pFirstBlock = pNextBlock;
}
}
T& operator[](int iIndex) {
static T dummy;
int iBaseNdx = iIndex & (~SVSUTIL_TIER_MASK);
SVSMTABlock<T> *pmta = m_pFirstBlock;
while (pmta) {
if (pmta->m_iNdxFirst == iBaseNdx)
return pmta->m_p_ptCollection[(iIndex & SVSUTIL_TIER_COLLECTION_MASK) >> SVSUTIL_TIER_ELEMENT_BIT][iIndex & SVSUTIL_TIER_ELEMENT_MASK];
pmta = pmta->m_pNextBlock;
}
return dummy;
}
};
template <class T> int SVSExpArray<T>::SRealloc (int a_iElemNum) {
SVSUTIL_ASSERT (a_iElemNum >= 0);
int iNeedBlocks = (a_iElemNum >> SVSUTIL_TIER_BIT) + 1;
if (iNeedBlocks < m_iBigBlocks)
return TRUE;
int iClusters = ((a_iElemNum & SVSUTIL_TIER_MASK) >> SVSUTIL_TIER_ELEMENT_BIT) + 1;
if ((iNeedBlocks == m_iBigBlocks) && (iClusters <= m_iPhysInLast))
return TRUE;
if (iNeedBlocks > m_iBigBlocks) {
if (m_pFirstBlock) {
while (m_iPhysInLast < SVSUTIL_TIER_COLLECTION_SIZE) {
if (! m_pFirstBlock->AllocateCluster(m_iPhysInLast)) {
SVSUTIL_ASSERT(0);
return FALSE;
}
++m_iPhysInLast;
}
}
while (m_iBigBlocks < iNeedBlocks) {
SVSMTABlock<T> *pNewFirst = new SVSMTABlock<T>(m_pFirstBlock, m_iBigBlocks << SVSUTIL_TIER_BIT);
if ((! pNewFirst) || (!pNewFirst->AllocateBlock())) {
SVSUTIL_ASSERT (0);
return FALSE;
}
++m_iBigBlocks;
m_pFirstBlock = pNewFirst;
m_iPhysInLast = 0;
int iLimit = (m_iBigBlocks < iNeedBlocks) ? SVSUTIL_TIER_COLLECTION_SIZE : iClusters;
while (m_iPhysInLast < iLimit) {
if (! m_pFirstBlock->AllocateCluster(m_iPhysInLast)) {
SVSUTIL_ASSERT(0);
return FALSE;
}
++m_iPhysInLast;
}
}
return TRUE;
}
while (m_iPhysInLast < iClusters) {
if (! m_pFirstBlock->AllocateCluster(m_iPhysInLast)) {
SVSUTIL_ASSERT(0);
return FALSE;
}
++m_iPhysInLast;
}
return TRUE;
}
template <class T> int SVSExpArray<T>::CRealloc (int a_iElemNum) {
SVSUTIL_ASSERT (a_iElemNum >= 0);
int iNeedBlocks = (a_iElemNum >> SVSUTIL_TIER_BIT) + 1;
if (iNeedBlocks > m_iBigBlocks)
return SRealloc (a_iElemNum);
int iClusters = ((a_iElemNum & SVSUTIL_TIER_MASK) >> SVSUTIL_TIER_ELEMENT_BIT) + 1;
if ((iNeedBlocks == m_iBigBlocks) && (iClusters > m_iPhysInLast))
return SRealloc (a_iElemNum);
while ((iNeedBlocks > m_iBigBlocks) && (m_iBigBlocks > 0)) {
SVSMTABlock<T> *pmta = m_pFirstBlock->m_pNextBlock;
delete m_pFirstBlock;
m_pFirstBlock = pmta;
--m_iBigBlocks;
m_iPhysInLast = SVSUTIL_TIER_COLLECTION_SIZE;
}
while (m_iPhysInLast > iClusters) {
SVSUTIL_ASSERT ((m_iPhysInLast == SVSUTIL_TIER_COLLECTION_SIZE) || (! m_pFirstBlock->m_p_ptCollection[m_iPhysInLast]));
--m_iPhysInLast;
SVSUTIL_ASSERT (m_pFirstBlock->m_p_ptCollection[m_iPhysInLast]);
g_funcFree (m_pFirstBlock->m_p_ptCollection[m_iPhysInLast], g_pvFreeData);
m_pFirstBlock->m_p_ptCollection[m_iPhysInLast] = NULL;
}
return TRUE;
}
//
// Long bitfields
//
class SVSBitField : public SVSAllocClass {
protected:
int m_iLength;
int m_iWLength;
unsigned int *m_puiData;
unsigned int m_uiLastWMask;
public:
SVSBitField (int a_iLength) {
SVSUTIL_ASSERT(a_iLength > 0);
m_iLength = a_iLength;
m_iWLength = (m_iLength / (8 * sizeof(int))) + 1;
m_uiLastWMask = ~((-1) << (m_iLength - (m_iWLength - 1) * 8 * sizeof(int)));
m_puiData = (unsigned int *)g_funcAlloc (m_iWLength * sizeof(int), g_pvAllocData);
}
~SVSBitField (void) {
g_funcFree (m_puiData, g_pvFreeData);
}
SVSBitField &operator=(int iBit) {
if ((iBit & 1) == 0)
memset (m_puiData, 0, m_iWLength * sizeof(int));
else
memset (m_puiData, 0xff, m_iWLength * sizeof(int));
return *this;
}
SVSBitField &operator=(SVSBitField &bf) {
SVSUTIL_ASSERT (bf.m_iLength == m_iLength);
memcpy (m_puiData, bf.m_puiData, m_iWLength * sizeof(int));
return *this;
}
SVSBitField &operator|=(SVSBitField &bf) {
SVSUTIL_ASSERT (bf.m_iLength == m_iLength);
for (int i = 0 ; i < m_iWLength ; ++i)
m_puiData[i] |= bf.m_puiData[i];
return *this;
}
SVSBitField &operator&=(SVSBitField &bf) {
SVSUTIL_ASSERT (bf.m_iLength == m_iLength);
for (int i = 0 ; i < m_iWLength ; ++i)
m_puiData[i] &= bf.m_puiData[i];
return *this;
}
void Set (int iBitNum) {
SVSUTIL_ASSERT (iBitNum < m_iLength);
int iWord = iBitNum / (sizeof(int) * 8);
unsigned int uiMask = 1 << (iBitNum - iWord * sizeof(int) * 8);
m_puiData[iWord] |= uiMask;
}
void Clear (int iBitNum) {
SVSUTIL_ASSERT (iBitNum < m_iLength);
int iWord = iBitNum / (sizeof(int) * 8);
unsigned int uiMask = 1 << (iBitNum - iWord * sizeof(int) * 8);
m_puiData[iWord] &= ~uiMask;
}
void Inv (int iBitNum) {
SVSUTIL_ASSERT (iBitNum < m_iLength);
int iWord = iBitNum / (sizeof(int) * 8);
unsigned int uiMask = 1 << (iBitNum - iWord * sizeof(int) * 8);
m_puiData[iWord] ^= uiMask;
}
int Get(int iBitNum) {
SVSUTIL_ASSERT (iBitNum < m_iLength);
int iWord = iBitNum / (sizeof(int) * 8);
return (m_puiData[iWord] >> (iBitNum - iWord * sizeof(int) * 8)) & 1;
}
int operator==(int iBit) {
unsigned int iCmp = ((iBit & 1) == 0) ? 0 : (unsigned int)-1;
for (int i = 0 ; i < m_iWLength - 1 ; ++i) {
if (m_puiData[i] != iCmp)
return FALSE;
}
return ((m_puiData[i] ^ iCmp) & m_uiLastWMask) == 0;
}
int operator!=(int iBit) {
return ! (*this == iBit);
}
int operator==(SVSBitField &bf) {
if (bf.m_iLength != m_iLength)
return FALSE;
for (int i = 0 ; i < m_iWLength - 1 ; ++i) {
if (m_puiData[i] != bf.m_puiData[i])
return FALSE;
}
return ((m_puiData[i] ^ bf.m_puiData[i]) & m_uiLastWMask) == 0;
}
int operator!=(SVSBitField &bf) {
return ! (*this == bf);
}
};
//
// Heaps
//
struct SVSHeapEntry {
SVSCKey cKey;
void *pvData;
};
class SVSHeap : public SVSAllocClass, public SVSEnumClass {
protected:
int heap_size;
SVSExpArray<SVSHeapEntry> *pArray;
static int Parent(int i) { return (i - 1) / 2; }
static int Left (int i) { return 2 * i + 1; }
static int Right (int i) { return 2 * (i + 1); }
void Heapify (int i) {
int l = Left(i);
int r = Right(i);
int largest = ((l < heap_size) && ((*pArray)[l].cKey > (*pArray)[i].cKey)) ? l : i;
if ((r < heap_size) && ((*pArray)[r].cKey > (*pArray)[largest].cKey))
largest = r;
if (largest != i) {
SVSHeapEntry he = (*pArray)[i];
(*pArray)[i] = (*pArray)[largest];
(*pArray)[largest] = he;
Heapify (largest);
}
}
public:
SVSHeap (void) {
heap_size = 0;
pArray = new SVSExpArray<SVSHeapEntry>;
}
~SVSHeap (void) {
delete pArray;
}
int Insert(SVSCKey cKey, void *pvData) {
if (! (*pArray).SRealloc(heap_size + 1))
return FALSE;
int i = heap_size++;
while ((i > 0) && ((*pArray)[Parent(i)].cKey < cKey)) {
(*pArray)[i] = (*pArray)[Parent(i)];
i = Parent(i);
}
(*pArray)[i].cKey = cKey;
(*pArray)[i].pvData = pvData;
return TRUE;
}
void *Remove(SVSHandle hIndex)
{
if (heap_size < 1 || (int) hIndex > heap_size) {
SVSUTIL_ASSERT(0);
return NULL;
}
hIndex = hIndex - 1;
void *pvResult = (*pArray)[hIndex].pvData;
--heap_size;
(*pArray)[hIndex] = (*pArray)[heap_size];
Heapify(hIndex);
return pvResult;
}
int IsEmpty (void) {
return heap_size < 1;
}
void *Peek (SVSCKey *pcKey) {
if (heap_size < 1) {
SVSUTIL_ASSERT(0);
return NULL;
}
if (pcKey)
*pcKey = (*pArray)[0].cKey;
return (*pArray)[0].pvData;
}
void *ExtractMax (SVSCKey *pcKey) {
if (heap_size < 1) {
SVSUTIL_ASSERT(0);
return NULL;
}
void *pvResult = (*pArray)[0].pvData;
if (pcKey)
*pcKey = (*pArray)[0].cKey;
--heap_size;
(*pArray)[0] = (*pArray)[heap_size];
Heapify (0);
return pvResult;
}
void Compact (void) {
(*pArray).CRealloc (heap_size);
}
virtual SVSHandle EnumStart (void) {
return heap_size < 1 ? SVSUTIL_HANDLE_INVALID : 1;
}
virtual SVSHandle EnumNext (SVSHandle hEnum) {
return (int)hEnum < heap_size ? hEnum + 1 : SVSUTIL_HANDLE_INVALID;
}
virtual void *EnumGetData (SVSHandle hEnum) {
SVSUTIL_ASSERT ((hEnum > 0) && ((int)hEnum <= heap_size));
return (*pArray)[hEnum - 1].pvData;
}
virtual SVSCKey EnumGetKey (SVSHandle hEnum) {
SVSUTIL_ASSERT ((hEnum > 0) && ((int)hEnum <= heap_size));
return (*pArray)[hEnum - 1].cKey;
}
};
//
// Heap template
//
template <class T> struct SVSTHeapEntry {
T cKey;
void *pvData;
};
template <class T> class SVSTHeap {
protected:
int heap_size;
typedef SVSTHeapEntry<T> X;
SVSExpArray<X> *pArray;
static int Parent(int i) { return (i - 1) / 2; }
static int Left (int i) { return 2 * i + 1; }
static int Right (int i) { return 2 * (i + 1); }
void Heapify (int i) {
int l = Left(i);
int r = Right(i);
int largest = ((l < heap_size) && ((*pArray)[l].cKey > (*pArray)[i].cKey)) ? l : i;
if ((r < heap_size) && ((*pArray)[r].cKey > (*pArray)[largest].cKey))
largest = r;
if (largest != i) {
SVSTHeapEntry<T> he = (*pArray)[i];
(*pArray)[i] = (*pArray)[largest];
(*pArray)[largest] = he;
Heapify (largest);
}
}
public:
SVSTHeap (void) {
heap_size = 0;
pArray = new SVSExpArray < SVSTHeapEntry<T> >;
}
~SVSTHeap (void) {
delete pArray;
}
int Insert(T cKey, void *pvData) {
if (! (*pArray).SRealloc(heap_size + 1))
return FALSE;
int i = heap_size++;
while ((i > 0) && ((*pArray)[Parent(i)].cKey < cKey)) {
(*pArray)[i] = (*pArray)[Parent(i)];
i = Parent(i);
}
(*pArray)[i].cKey = cKey;
(*pArray)[i].pvData = pvData;
return TRUE;
}
void *Remove(SVSHandle hIndex)
{
if (heap_size < 1 || (int) hIndex > heap_size) {
SVSUTIL_ASSERT(0);
return NULL;
}
hIndex = hIndex - 1;
void *pvResult = (*pArray)[hIndex].pvData;
--heap_size;
(*pArray)[hIndex] = (*pArray)[heap_size];
Heapify(hIndex);
return pvResult;
}
int IsEmpty (void) {
return heap_size < 1;
}
void *Peek (T *pcKey) {
if (heap_size < 1) {
SVSUTIL_ASSERT(0);
return NULL;
}
if (pcKey)
*pcKey = (*pArray)[0].cKey;
return (*pArray)[0].pvData;
}
void *ExtractMax (T *pcKey) {
if (heap_size < 1) {
SVSUTIL_ASSERT(0);
return NULL;
}
void *pvResult = (*pArray)[0].pvData;
if (pcKey)
*pcKey = (*pArray)[0].cKey;
--heap_size;
(*pArray)[0] = (*pArray)[heap_size];
Heapify (0);
return pvResult;
}
void Compact (void) {
(*pArray).CRealloc (heap_size);
}
virtual SVSHandle EnumStart (void) {
return heap_size < 1 ? SVSUTIL_HANDLE_INVALID : 1;
}
virtual SVSHandle EnumNext (SVSHandle hEnum) {
return (int)hEnum < heap_size ? hEnum + 1 : SVSUTIL_HANDLE_INVALID;
}
virtual void *EnumGetData (SVSHandle hEnum) {
SVSUTIL_ASSERT ((hEnum > 0) && ((int)hEnum <= heap_size));
return (*pArray)[hEnum - 1].pvData;
}
virtual T EnumGetKey (SVSHandle hEnum) {
SVSUTIL_ASSERT ((hEnum > 0) && ((int)hEnum <= heap_size));
return (*pArray)[hEnum - 1].cKey;
}
};
//
// Handle system
//
#define SVSUTIL_HANDLE_NUMBITS 16
#define SVSUTIL_HANDLE_TAGBITS (sizeof(SVSHandle) * 8 - SVSUTIL_HANDLE_NUMBITS)
#define SVSUTIL_HANDLE_MAXNUM ((1 << SVSUTIL_HANDLE_NUMBITS) - 1)
#define SVSUTIL_HANDLE_MAXTAG ((1 << SVSUTIL_HANDLE_TAGBITS) - 1)
#define SVSUTIL_HANDLE_TOTAG(h) ((h) >> SVSUTIL_HANDLE_NUMBITS)
#define SVSUTIL_HANDLE_TONUM(h) ((h) & SVSUTIL_HANDLE_MAXNUM)
class SVSPrivateHandle : public SVSAllocClass {
protected:
union {
void *pvData;
int iNextFree;
};
struct {
int iTag : 24;
unsigned int fFree : 1;
};
friend class SVSHandleSystem;
friend class SVSSimpleHandleSystem;
};
class SVSHandleSystem : public SVSAllocClass {
protected:
SVSExpArray<SVSPrivateHandle> *pArray;
int iFreeNdx;
int iArraySize;
public:
SVSHandle AllocHandle (void *a_pvData) {
SVSUTIL_ASSERT (a_pvData != NULL);
SVSUTIL_ASSERT (iFreeNdx < iArraySize);
SVSUTIL_ASSERT (iArraySize >= 0);
if (iFreeNdx == -1) {
if (iArraySize >= SVSUTIL_HANDLE_MAXNUM)
return FALSE;
if (! (*pArray).SRealloc (iArraySize + 1))
return SVSUTIL_HANDLE_INVALID;
iFreeNdx = iArraySize;
(*pArray)[iArraySize].iNextFree = -1;
(*pArray)[iArraySize].iTag = 1;
(*pArray)[iArraySize].fFree = TRUE;
++iArraySize;
}
SVSUTIL_ASSERT ((iFreeNdx >= 0) && (iFreeNdx < iArraySize));
SVSPrivateHandle *psHandle = &(*pArray)[iFreeNdx];
int iNdx = iFreeNdx;
SVSUTIL_ASSERT (psHandle->fFree);
iFreeNdx = psHandle->iNextFree;
psHandle->pvData = a_pvData;
psHandle->fFree = FALSE;
psHandle->iTag += 1;
if (psHandle->iTag >= SVSUTIL_HANDLE_MAXTAG)
psHandle->iTag = 1;
return (psHandle->iTag << SVSUTIL_HANDLE_NUMBITS) | iNdx;
}
void *CloseHandle (SVSHandle h) {
SVSUTIL_ASSERT (iFreeNdx < iArraySize);
int iTag = SVSUTIL_HANDLE_TOTAG(h);
int iNum = SVSUTIL_HANDLE_TONUM(h);
if ((iNum >= iArraySize) || (iTag != (*pArray)[iNum].iTag))
return NULL;
SVSUTIL_ASSERT (iArraySize > 0);
SVSPrivateHandle *psHandle = &(*pArray)[iNum];
void *pvData = psHandle->pvData;
SVSUTIL_ASSERT (! psHandle->fFree);
psHandle->iNextFree = iFreeNdx;
psHandle->fFree = TRUE;
iFreeNdx = iNum;
if (++psHandle->iTag >= SVSUTIL_HANDLE_MAXTAG)
psHandle->iTag = 1;
return pvData;
}
void *TranslateHandle (SVSHandle h) {
SVSUTIL_ASSERT (iFreeNdx < iArraySize);
int iTag = SVSUTIL_HANDLE_TOTAG(h);
int iNum = SVSUTIL_HANDLE_TONUM(h);
if ((iNum >= iArraySize) || (iTag != (*pArray)[iNum].iTag))
return NULL;
SVSUTIL_ASSERT (iArraySize > 0);
SVSUTIL_ASSERT (! (*pArray)[iNum].fFree);
return (*pArray)[iNum].pvData;
}
void *ReAssociate (SVSHandle h, void *pvData2) {
SVSUTIL_ASSERT (iFreeNdx < iArraySize);
SVSUTIL_ASSERT (pvData2 != NULL);
int iTag = SVSUTIL_HANDLE_TOTAG(h);
int iNum = SVSUTIL_HANDLE_TONUM(h);
if ((iNum >= iArraySize) || (iTag != (*pArray)[iNum].iTag))
return NULL;
SVSUTIL_ASSERT (iArraySize > 0);
SVSUTIL_ASSERT (! (*pArray)[iNum].fFree);
void *pvResult = (*pArray)[iNum].pvData;
(*pArray)[iNum].pvData = pvData2;
return pvResult;
}
int FilterHandles (int (*pFuncFilter)(SVSHandle, void *), void *pvArg) {
unsigned int iProcessed = 0;
for (int i = 0 ; i < iArraySize ; ++i) {
if (! (*pArray)[i].fFree)
iProcessed += pFuncFilter (((*pArray)[i].iTag << SVSUTIL_HANDLE_NUMBITS) | i,
pvArg);
}
return iProcessed;
}
SVSHandleSystem (void) {
pArray = new SVSExpArray<SVSPrivateHandle>;
iFreeNdx = -1;
iArraySize = 0;
}
~SVSHandleSystem (void) {
delete pArray;
}
};
class SVSSimpleHandleSystem : public SVSAllocClass {
protected:
SVSPrivateHandle *pArray;
int iFreeNdx;
int iArraySize;
int iMaxArraySize;
public:
SVSHandle AllocHandle (void *a_pvData) {
SVSUTIL_ASSERT (a_pvData != NULL);
SVSUTIL_ASSERT (iFreeNdx < iArraySize);
SVSUTIL_ASSERT (iArraySize >= 0);
if (iFreeNdx == -1) {
if (iArraySize >= iMaxArraySize)
return FALSE;
iFreeNdx = iArraySize;
pArray[iArraySize].iNextFree = -1;
pArray[iArraySize].iTag = 1;
pArray[iArraySize].fFree = TRUE;
++iArraySize;
}
SVSUTIL_ASSERT ((iFreeNdx >= 0) && (iFreeNdx < iArraySize));
SVSPrivateHandle *psHandle = &pArray[iFreeNdx];
int iNdx = iFreeNdx;
SVSUTIL_ASSERT (psHandle->fFree);
iFreeNdx = psHandle->iNextFree;
psHandle->pvData = a_pvData;
psHandle->fFree = FALSE;
psHandle->iTag += 1;
if (psHandle->iTag >= SVSUTIL_HANDLE_MAXTAG)
psHandle->iTag = 1;
return (psHandle->iTag << SVSUTIL_HANDLE_NUMBITS) | iNdx;
}
void *CloseHandle (SVSHandle h) {
SVSUTIL_ASSERT (iFreeNdx < iArraySize);
int iTag = SVSUTIL_HANDLE_TOTAG(h);
int iNum = SVSUTIL_HANDLE_TONUM(h);
if ((iNum >= iArraySize) || (iTag != pArray[iNum].iTag))
return NULL;
SVSUTIL_ASSERT (iArraySize > 0);
SVSPrivateHandle *psHandle = &pArray[iNum];
void *pvData = psHandle->pvData;
SVSUTIL_ASSERT (! psHandle->fFree);
psHandle->iNextFree = iFreeNdx;
psHandle->fFree = TRUE;
iFreeNdx = iNum;
if (++psHandle->iTag >= SVSUTIL_HANDLE_MAXTAG)
psHandle->iTag = 1;
return pvData;
}
void *TranslateHandle (SVSHandle h) {
SVSUTIL_ASSERT (iFreeNdx < iArraySize);
int iTag = SVSUTIL_HANDLE_TOTAG(h);
int iNum = SVSUTIL_HANDLE_TONUM(h);
if ((iNum >= iArraySize) || (iTag != pArray[iNum].iTag))
return NULL;
SVSUTIL_ASSERT (iArraySize > 0);
SVSUTIL_ASSERT (! pArray[iNum].fFree);
return pArray[iNum].pvData;
}
void *ReAssociate (SVSHandle h, void *pvData2) {
SVSUTIL_ASSERT (iFreeNdx < iArraySize);
SVSUTIL_ASSERT (pvData2 != NULL);
int iTag = SVSUTIL_HANDLE_TOTAG(h);
int iNum = SVSUTIL_HANDLE_TONUM(h);
if ((iNum >= iArraySize) || (iTag != pArray[iNum].iTag))
return NULL;
SVSUTIL_ASSERT (iArraySize > 0);
SVSUTIL_ASSERT (! pArray[iNum].fFree);
void *pvResult = pArray[iNum].pvData;
pArray[iNum].pvData = pvData2;
return pvResult;
}
int FilterHandles (int (*pFuncFilter)(SVSHandle, void *), void *pvArg) {
unsigned int iProcessed = 0;
for (int i = 0 ; i < iArraySize ; ++i) {
if (! pArray[i].fFree)
iProcessed += pFuncFilter ((pArray[i].iTag << SVSUTIL_HANDLE_NUMBITS) | i,
pvArg);
}
return iProcessed;
}
SVSSimpleHandleSystem (int a_iMaxArraySize) {
pArray = (SVSPrivateHandle *)g_funcAlloc (sizeof(SVSPrivateHandle) * a_iMaxArraySize, g_pvAllocData);
iFreeNdx = -1;
iArraySize = 0;
iMaxArraySize = a_iMaxArraySize;
}
~SVSSimpleHandleSystem (void) {
g_funcFree (pArray, g_pvFreeData);
}
};
#define SVSUTIL_PGUID_ELEMENTS(p) \
p->Data1, p->Data2, p->Data3,\
p->Data4[0], p->Data4[1], p->Data4[2], p->Data4[3],\
p->Data4[4], p->Data4[5], p->Data4[6], p->Data4[7]
#define SVSUTIL_RGUID_ELEMENTS(p) \
p.Data1, p.Data2, p.Data3,\
p.Data4[0], p.Data4[1], p.Data4[2], p.Data4[3],\
p.Data4[4], p.Data4[5], p.Data4[6], p.Data4[7]
#define SVSUTIL_GUID_FORMAT L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x"
#define SVSUTIL_GUID_STR_LENGTH (8 + 1 + 4 + 1 + 4 + 1 + 4 + 1 + 12)
//
// C-like interface
//
extern "C" {
SVSQueue *svsutil_GetQueue (unsigned int uiChunkSize);
int svsutil_IsQueueEmpty (SVSQueue *pQueue);
int svsutil_PutInQueue (SVSQueue *pQueue, void *pvDatum);
void *svsutil_GetFromQueue (SVSQueue *pQueue);
void *svsutil_PeekQueue (SVSQueue *pQueue);
void svsutil_CompactQueue (SVSQueue *pQueue);
void svsutil_DestroyQueue (SVSQueue *pQueue);
SVSStack *svsutil_GetStack (unsigned int uiChunkSize);
int svsutil_IsStackEmpty (SVSStack *pStack);
int svsutil_PushStack (SVSStack *pStack, void *pvDatum);
void *svsutil_PopStack (SVSStack *pStack);
void *svsutil_PeekStack (SVSStack *pStack);
void svsutil_CompactStack (SVSStack *pStack);
void svsutil_DestroyStack (SVSStack *pStack);
SVSStack *svsutil_GetHeap (void);
int svsutil_IsHeapEmpty (SVSHeap *pHeap);
int svsutil_InsertInHeap (SVSHeap *pHeap, SVSCKey *pcKey, void *pvDatum);
void *svsutil_ExtractMaxFromHeap (SVSHeap *pHeap, SVSCKey *pcKey);
void *svsutil_PeekHeap (SVSHeap *pHeap, SVSCKey *pcKet);
void svsutil_CompactHeap (SVSHeap *pHeap);
void svsutil_DestroyHeap (SVSHeap *pHeap);
}
//
// Thread pool
//
// For converting between filetime and tick measurements
#define SVS_FILETIME_TO_MILLISECONDS ((__int64)10000L)
#if defined (UNDER_CE) && !defined (InterlockedCompareExchange)
#define InterlockedCompareExchange(ptr, newval, oldval) \
((PVOID)InterlockedTestExchange((LPLONG)ptr, (LONG)oldval, (LONG)newval))
#endif
typedef unsigned long SVSCookie;
#define SVS_DEBUG_THREAD_WORKER 0
#define SVS_DEBUG_THREAD_SCHEDULE_EVENT 0
#define SVS_DEBUG_THREAD_QUEUE 0
#define SVS_THREAD_POOL_DEFAULT_MAX_THREADS 20
class SVSThreadBlock
{
friend class SVSThreadPool;
protected:
LPTHREAD_START_ROUTINE m_pfnThread;
LPVOID m_lpParameter;
SVSCookie m_ulCookie;
unsigned long Run() {
SVSUTIL_ASSERT (m_pfnThread && m_ulCookie);
return (m_pfnThread)(m_lpParameter);
}
};
inline __int64 SVSGetCurrentFT(void)
{
SYSTEMTIME st;
__int64 ft;
GetSystemTime(&st);
SystemTimeToFileTime(&st,(LPFILETIME) &ft);
return ft;
}
// User application uses this in GetStatistics
typedef struct
{
LONG fRunning;
unsigned long cThreadsRunning;
unsigned long cThreadsIdle;
unsigned long ulAverageDelayTime;
long cJobsExecuted;
} SVS_THREAD_POOL_STATS;
//
// Used internally by SVSThreadPool for statistics
//
#define SVS_THREAD_STATS_RESIZE 5
class CSVSThreadPoolInternalStats
{
double m_dAvgArray[2];
__int64 m_ftPrev;
int m_iSlot;
int m_iIndex;
long m_cJobsExecuted;
public:
CSVSThreadPoolInternalStats() {
memset(this,0,sizeof(*this));
}
// Called with Lock held by caller.
void UpdateStatistics(void) {
__int64 ftNow = SVSGetCurrentFT();
__int64 ftDelta;
m_cJobsExecuted++;
ftDelta = m_ftPrev ? ftNow - m_ftPrev : 0;
m_ftPrev = ftNow;
m_dAvgArray[m_iSlot] += ftDelta;
m_iIndex++;
if (m_iIndex == SVS_THREAD_STATS_RESIZE)
{
m_dAvgArray[m_iSlot] /= SVS_THREAD_STATS_RESIZE;
m_iSlot = (m_iSlot + 1) % 2;
m_dAvgArray[m_iSlot] = 0;
m_iIndex = 0;
}
}
// Called with Lock held by caller.
double CalculateAverageDelay(void) {
double dRet;
if (m_cJobsExecuted == 0)
{
dRet = 0;
}
else if (m_cJobsExecuted < SVS_THREAD_STATS_RESIZE)
{
dRet = m_dAvgArray[0] / m_cJobsExecuted;
}
else
{
dRet = (m_dAvgArray[!m_iSlot]*SVS_THREAD_STATS_RESIZE +
m_dAvgArray[m_iSlot]) / (m_iIndex + SVS_THREAD_STATS_RESIZE);
}
return (double) (dRet / SVS_FILETIME_TO_MILLISECONDS);
}
int NumberOfJobsExecuted(void) {
return m_cJobsExecuted;
}
};
class SVSThreadPool : public SVSSynch, public SVSAllocClass, public SVSTHeap<__int64>
{
protected:
FixedMemDescr *m_pNodeMem; // physical memory of SVSThreadBlock structures, both ones in use and not.
HANDLE m_hWorkerEvent; // signals running worker threads we're ready
HANDLE m_hTimerEvent; // signals running worker threads we're ready
long m_fRunning; // Are we accepting new thread requests?
unsigned long m_cMaxThreadsAllowed; // Maximum # of threads to allow
unsigned long m_cThreadsRunning; // # of threads executing user code
unsigned long m_cThreadsIdle; // # of threads not executing user code but available.
SVSCookie m_ulCookie; // Value of next cookie to assign
long m_fTimerLock; // Used to sync which worker is the timer
#if defined (SVSUTIL_DEBUG_THREADS)
CSVSThreadPoolInternalStats m_Stats; // Perf statistics.
#endif
BOOL GetTimer(void) {
return !InterlockedCompareExchange(&m_fTimerLock,1,0);
}
void ReleaseTimer(void) {
m_fTimerLock = 0;
}
// BUGBUG -- what happens if someone changes system time??
// Called with Lock held by caller.
SVSThreadBlock * GetNextJobFromQueue()
{
SVSUTIL_ASSERT(IsLocked());
__int64 ftNow;
__int64 ftNextEvent;
SVSThreadBlock *ret;
if (IsEmpty() || !m_fRunning)
return NULL;
ret = (SVSThreadBlock *) Peek(&ftNextEvent);
ftNow = SVSGetCurrentFT();
if (ftNow >= ~ftNextEvent)
{
ExtractMax(NULL);
}
else
{
ret = NULL;
}
return ret;
}
// Called with Lock held by caller.
SVSCookie PutOnWorkerQueue(LPTHREAD_START_ROUTINE pfn, LPVOID lpParameter,__int64 ftExecuteTime)
{
SVSUTIL_ASSERT(IsLocked());
SVSThreadBlock *pThreadBlock = (SVSThreadBlock *)svsutil_GetFixed (m_pNodeMem);
pThreadBlock->m_pfnThread = pfn;
pThreadBlock->m_lpParameter = lpParameter;
pThreadBlock->m_ulCookie = ++m_ulCookie;
if (! Insert(~ftExecuteTime,pThreadBlock))
return 0;
if (m_cThreadsRunning == 0 && m_cThreadsIdle == 0)
{
HANDLE hThread = CreateThread(0,0,SVSThreadPoolWorkerThread,this,0,0);
SVSUTIL_ASSERT (hThread);
if (hThread)
{
CloseHandle(hThread);
m_cThreadsIdle++;
}
}
SetEvent(m_hTimerEvent);
return pThreadBlock->m_ulCookie;
}
// Called with Lock held by caller.
unsigned long GetDelayUntilNextEvent()
{
SVSUTIL_ASSERT(IsLocked());
__int64 ftNow;
__int64 ftNextEvent;
if (IsEmpty())
return INFINITE;
Peek(&ftNextEvent);
ftNextEvent = ~ftNextEvent;
ftNow = SVSGetCurrentFT();
// if event has passed, set to 0 timeout.
if (ftNow >= ftNextEvent)
return 0;
return (unsigned long) ((ftNextEvent - ftNow) / SVS_FILETIME_TO_MILLISECONDS);
}
void Worker()
{
SVSThreadBlock *pThreadBlock = NULL;
BOOL fTimer;
unsigned long ulTimeOut;
HANDLE hEvent;
while (m_fRunning)
{
fTimer = GetTimer();
if (fTimer)
{
hEvent = m_hTimerEvent;
Lock();
ulTimeOut = GetDelayUntilNextEvent();
Unlock();
}
else
{
ulTimeOut = 5*60000;
hEvent = m_hWorkerEvent;
}
if (WAIT_TIMEOUT == WaitForSingleObject(hEvent,ulTimeOut))
{
// If we're not the timer thread then we're done executing...
if (!fTimer)
{
break;
}
}
else if (!fTimer)
{
// We get the worker thread event if a timer has been freed
// or if we're shutting down, in either case we want
// to go to top of while loop.
continue;
}
SVSUTIL_ASSERT(fTimer);
ReleaseTimer();
Lock();
pThreadBlock = GetNextJobFromQueue();
if (!pThreadBlock)
{
Unlock();
continue;
}
m_cThreadsIdle--;
m_cThreadsRunning++;
if (m_cThreadsIdle)
{
SetEvent(m_hWorkerEvent);
}
else if (m_cThreadsRunning < m_cMaxThreadsAllowed)
{
HANDLE hThread = CreateThread(0,0,SVSThreadPoolWorkerThread,this,0,0);
SVSUTIL_ASSERT (hThread);
if (hThread)
{
CloseHandle(hThread);
m_cThreadsIdle++;
}
}
#if defined (SVSUTIL_DEBUG_THREADS)
m_Stats.UpdateStatistics();
#endif
Unlock();
pThreadBlock->Run();
Lock();
svsutil_FreeFixed(pThreadBlock,m_pNodeMem);
m_cThreadsIdle++;
m_cThreadsRunning--;
Unlock();
}
Lock(); m_cThreadsIdle--; Unlock();
}
static unsigned long WINAPI SVSThreadPoolWorkerThread(LPVOID lpv)
{
SVSThreadPool *pThreadPool = (SVSThreadPool *) lpv;
pThreadPool->Worker();
return 0;
}
public:
SVSThreadPool (unsigned long ulMaxThreads=SVS_THREAD_POOL_DEFAULT_MAX_THREADS)
{
m_cMaxThreadsAllowed = ulMaxThreads;
m_hTimerEvent = m_hWorkerEvent = 0;
m_cThreadsIdle = m_cThreadsRunning = m_ulCookie = 0;
m_fTimerLock = FALSE;
m_pNodeMem = svsutil_AllocFixedMemDescr (sizeof(SVSThreadBlock), 20);
pArray = new SVSExpArray<X>; // typedef SVSTHeapEntry<__int64> X;
m_hWorkerEvent = CreateEvent (0, FALSE, FALSE, 0);
m_hTimerEvent = CreateEvent (0, FALSE, FALSE, 0);
SVSUTIL_ASSERT ( m_pNodeMem && pArray && m_hWorkerEvent && m_hTimerEvent);
if (m_pNodeMem && pArray && m_hWorkerEvent && m_hTimerEvent)
{
m_fRunning = TRUE;
}
}
~SVSThreadPool()
{
Shutdown();
SVSUTIL_ASSERT (m_cThreadsRunning == 0 && m_cThreadsIdle == 0);
if (m_pNodeMem)
svsutil_ReleaseFixedNonEmpty(m_pNodeMem);
if (m_hWorkerEvent)
CloseHandle (m_hWorkerEvent);
if (m_hTimerEvent)
CloseHandle (m_hTimerEvent);
}
// Shutdown all timers and running threads. Once shutdown has started,
// no threads or timers may ever fire again
unsigned long Shutdown()
{
m_fRunning = FALSE;
while (m_cThreadsRunning || m_cThreadsIdle)
{
SetEvent(m_hTimerEvent);
SetEvent(m_hWorkerEvent);
Sleep(1000);
}
return TRUE;
}
SVSCookie ScheduleEvent(LPTHREAD_START_ROUTINE pfn, LPVOID lpParameter, unsigned long ulDelayTime=0)
{
SVSCookie ret = 0;
__int64 ftExecuteTime;
if (!m_fRunning)
{
return 0;
}
ftExecuteTime = SVSGetCurrentFT();
ftExecuteTime += ulDelayTime * SVS_FILETIME_TO_MILLISECONDS;
Lock();
ret = PutOnWorkerQueue(pfn,lpParameter,ftExecuteTime);
Unlock();
return ret;
}
SVSCookie StartTimer(LPTHREAD_START_ROUTINE pfn, LPVOID lpParameter,unsigned long ulDelayTime)
{
return ScheduleEvent(pfn,lpParameter,ulDelayTime);
}
BOOL UnScheduleEvent(SVSCookie ulCookie)
{
BOOL ret = FALSE;
SVSHandle hEnum;
SVSThreadBlock *pThreadBlock;
Lock();
hEnum = EnumStart();
do
{
pThreadBlock = (SVSThreadBlock *)EnumGetData(hEnum);
if (pThreadBlock->m_ulCookie == ulCookie)
{
ret = Remove(hEnum) ? TRUE : FALSE;
break;
}
} while (SVSUTIL_HANDLE_INVALID != (hEnum = EnumNext(hEnum)));
Unlock();
return ret;
}
BOOL StopTimer(SVSCookie ulCookie)
{
return UnScheduleEvent(ulCookie);
}
#if defined (SVSUTIL_DEBUG_THREADS)
public:
void GetStatistics(SVS_THREAD_POOL_STATS *pThreadStats)
{
if (!pThreadStats)
return;
Lock();
pThreadStats->fRunning = m_fRunning;
pThreadStats->cThreadsRunning = m_cThreadsRunning;
pThreadStats->cThreadsIdle = m_cThreadsIdle;
pThreadStats->ulAverageDelayTime = (unsigned long) m_Stats.CalculateAverageDelay();
pThreadStats->cJobsExecuted = m_Stats.NumberOfJobsExecuted();
Unlock();
}
#endif // SVSUTIL_DEBUG_THREADS
};
#else /* __cplusplus */
struct SVSQueue;
struct SVSStack;
struct SVSHeap;
struct SVSQueue *svsutil_GetQueue (unsigned int uiChunkSize);
int svsutil_IsQueueEmpty (struct SVSQueue *pQueue);
int svsutil_PutInQueue (struct SVSQueue *pQueue, void *pvDatum);
void *svsutil_GetFromQueue (struct SVSQueue *pQueue);
void *svsutil_PeekQueue (struct SVSQueue *pQueue);
void svsutil_CompactQueue (struct SVSQueue *pQueue);
void svsutil_DestroyQueue (struct SVSQueue *pQueue);
struct SVSStack *svsutil_GetStack (unsigned int uiChunkSize);
int svsutil_IsStackEmpty (struct SVSStack *pStack);
int svsutil_PushStack (struct SVSStack *pStack, void *pvDatum);
void *svsutil_PopStack (struct SVSStack *pStack);
void *svsutil_PeekStack (struct SVSStack *pStack);
void svsutil_CompactStack (struct SVSStack *pStack);
void svsutil_DestroyStack (struct SVSStack *pStack);
struct SVSStack *svsutil_GetHeap (void);
int svsutil_IsHeapEmpty (struct SVSHeap *pHeap);
int svsutil_InsertInHeap (struct SVSHeap *pHeap, SVSCKey *pcKey, void *pvDatum);
void *svsutil_ExtractMaxFromHeap (struct SVSHeap *pHeap, SVSCKey *pcKey);
void *svsutil_PeekHeap (struct SVSHeap *pHeap, SVSCKey *pcKet);
void svsutil_CompactHeap (struct SVSHeap *pHeap);
void svsutil_DestroyHeap (struct SVSHeap *pHeap);
#endif
#endif /* __svsutil_HXX__ */