/*++ 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 #if ! defined (UNDER_CE) #include #include #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 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 SVSExpArray : public SVSAllocClass { protected: int m_iBigBlocks; int m_iPhysInLast; SVSMTABlock *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 *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 *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 int SVSExpArray::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 *pNewFirst = new SVSMTABlock(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 int SVSExpArray::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 *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 *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; } ~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 struct SVSTHeapEntry { T cKey; void *pvData; }; template class SVSTHeap { protected: int heap_size; typedef SVSTHeapEntry X; SVSExpArray *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 he = (*pArray)[i]; (*pArray)[i] = (*pArray)[largest]; (*pArray)[largest] = he; Heapify (largest); } } public: SVSTHeap (void) { heap_size = 0; pArray = new SVSExpArray < SVSTHeapEntry >; } ~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 *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; 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; // 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__ */