|
|
/*++
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__ */
|