481 lines
10 KiB
C++
481 lines
10 KiB
C++
/*++
|
|
|
|
Copyright (c) 1998 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
tpsclass.h
|
|
|
|
Abstract:
|
|
|
|
Basic classes for Win32 thread pool services functions
|
|
|
|
Contents:
|
|
CCriticalSection_NoCtor
|
|
CCriticalSection
|
|
CDoubleLinkedListEntry
|
|
CDoubleLinkedList
|
|
CTimedListEntry
|
|
CTimedList
|
|
CPrioritizedListEntry
|
|
CPrioritizedList
|
|
|
|
Author:
|
|
|
|
Richard L Firth (rfirth) 11-Feb-1998
|
|
|
|
Notes:
|
|
|
|
Some of these classes have no constructor so that we avoid requiring global
|
|
object initialization (via main() e.g.) Therefore, these objects must be
|
|
explicitly initialized through the Init() member
|
|
|
|
Revision History:
|
|
|
|
11-Feb-1998 rfirth
|
|
Created
|
|
|
|
--*/
|
|
|
|
// These linked-list helper macros and types are taken from
|
|
// ntdef.h and ntrtl.h. We don't want to include those because
|
|
// we have no other reason, and including the nt headers as a
|
|
// win32 component causes compilation conflicts.
|
|
|
|
//
|
|
// VOID
|
|
// InitializeListHead(
|
|
// PLIST_ENTRY ListHead
|
|
// );
|
|
//
|
|
|
|
#define InitializeListHead(ListHead) (\
|
|
(ListHead)->Flink = (ListHead)->Blink = (ListHead))
|
|
|
|
//
|
|
// BOOLEAN
|
|
// IsListEmpty(
|
|
// PLIST_ENTRY ListHead
|
|
// );
|
|
//
|
|
|
|
#define IsListEmpty(ListHead) \
|
|
((ListHead)->Flink == (ListHead))
|
|
|
|
//
|
|
// PLIST_ENTRY
|
|
// RemoveHeadList(
|
|
// PLIST_ENTRY ListHead
|
|
// );
|
|
//
|
|
|
|
#define RemoveHeadList(ListHead) \
|
|
(ListHead)->Flink;\
|
|
{RemoveEntryList((ListHead)->Flink)}
|
|
|
|
//
|
|
// PLIST_ENTRY
|
|
// RemoveTailList(
|
|
// PLIST_ENTRY ListHead
|
|
// );
|
|
//
|
|
|
|
#define RemoveTailList(ListHead) \
|
|
(ListHead)->Blink;\
|
|
{RemoveEntryList((ListHead)->Blink)}
|
|
|
|
//
|
|
// VOID
|
|
// RemoveEntryList(
|
|
// PLIST_ENTRY Entry
|
|
// );
|
|
//
|
|
|
|
#define RemoveEntryList(Entry) {\
|
|
PLIST_ENTRY _EX_Blink;\
|
|
PLIST_ENTRY _EX_Flink;\
|
|
_EX_Flink = (Entry)->Flink;\
|
|
_EX_Blink = (Entry)->Blink;\
|
|
_EX_Blink->Flink = _EX_Flink;\
|
|
_EX_Flink->Blink = _EX_Blink;\
|
|
}
|
|
|
|
//
|
|
// VOID
|
|
// InsertTailList(
|
|
// PLIST_ENTRY ListHead,
|
|
// PLIST_ENTRY Entry
|
|
// );
|
|
//
|
|
|
|
#define InsertTailList(ListHead,Entry) {\
|
|
PLIST_ENTRY _EX_Blink;\
|
|
PLIST_ENTRY _EX_ListHead;\
|
|
_EX_ListHead = (ListHead);\
|
|
_EX_Blink = _EX_ListHead->Blink;\
|
|
(Entry)->Flink = _EX_ListHead;\
|
|
(Entry)->Blink = _EX_Blink;\
|
|
_EX_Blink->Flink = (Entry);\
|
|
_EX_ListHead->Blink = (Entry);\
|
|
}
|
|
|
|
//
|
|
// VOID
|
|
// InsertHeadList(
|
|
// PLIST_ENTRY ListHead,
|
|
// PLIST_ENTRY Entry
|
|
// );
|
|
//
|
|
|
|
#define InsertHeadList(ListHead,Entry) {\
|
|
PLIST_ENTRY _EX_Flink;\
|
|
PLIST_ENTRY _EX_ListHead;\
|
|
_EX_ListHead = (ListHead);\
|
|
_EX_Flink = _EX_ListHead->Flink;\
|
|
(Entry)->Flink = _EX_Flink;\
|
|
(Entry)->Blink = _EX_ListHead;\
|
|
_EX_Flink->Blink = (Entry);\
|
|
_EX_ListHead->Flink = (Entry);\
|
|
}
|
|
|
|
//
|
|
// data
|
|
//
|
|
|
|
extern const char g_cszShlwapi[];
|
|
extern DWORD g_ActiveRequests;
|
|
extern DWORD g_dwTerminationThreadId;
|
|
extern BOOL g_bTpsTerminating;
|
|
extern BOOL g_bDeferredWorkerTermination;
|
|
extern BOOL g_bDeferredWaiterTermination;
|
|
extern BOOL g_bDeferredTimerTermination;
|
|
|
|
EXTERN_C DWORD g_TpsTls;
|
|
EXTERN_C BOOL g_bDllTerminating;
|
|
|
|
//
|
|
// macros
|
|
//
|
|
|
|
#if !defined(ARRAY_ELEMENTS)
|
|
#define ARRAY_ELEMENTS(array) (sizeof(array)/sizeof(array[0]))
|
|
#endif
|
|
|
|
#if !defined(LAST_ELEMENT)
|
|
#define LAST_ELEMENT(array) (ARRAY_ELEMENTS(array) - 1)
|
|
#endif
|
|
|
|
#if !defined(FT2LL)
|
|
#define FT2LL(x) (*(LONGLONG *)&(x))
|
|
#endif
|
|
|
|
//
|
|
// classes
|
|
//
|
|
|
|
//
|
|
// CCriticalSection_NoCtor - critical section class without constructor or
|
|
// destructor for use in global variables
|
|
//
|
|
|
|
class CCriticalSection_NoCtor {
|
|
|
|
private:
|
|
|
|
CRITICAL_SECTION m_critsec;
|
|
|
|
public:
|
|
|
|
VOID Init(VOID) {
|
|
InitializeCriticalSection(&m_critsec);
|
|
}
|
|
|
|
VOID Terminate(VOID) {
|
|
DeleteCriticalSection(&m_critsec);
|
|
}
|
|
|
|
VOID Acquire(VOID) {
|
|
EnterCriticalSection(&m_critsec);
|
|
}
|
|
|
|
VOID Release(VOID) {
|
|
LeaveCriticalSection(&m_critsec);
|
|
}
|
|
};
|
|
|
|
//
|
|
// CCriticalSection
|
|
//
|
|
|
|
class CCriticalSection : public CCriticalSection_NoCtor {
|
|
|
|
public:
|
|
|
|
CCriticalSection() {
|
|
Init();
|
|
}
|
|
|
|
~CCriticalSection() {
|
|
Terminate();
|
|
}
|
|
};
|
|
|
|
//
|
|
// CDoubleLinkedListEntry/CDoubleLinkedList
|
|
//
|
|
|
|
#define CDoubleLinkedList CDoubleLinkedListEntry
|
|
|
|
class CDoubleLinkedListEntry {
|
|
|
|
private:
|
|
|
|
LIST_ENTRY m_List;
|
|
|
|
public:
|
|
|
|
VOID Init(VOID) {
|
|
InitializeListHead(&m_List);
|
|
}
|
|
|
|
CDoubleLinkedListEntry * Head(VOID) {
|
|
return (CDoubleLinkedListEntry *)&m_List;
|
|
}
|
|
|
|
CDoubleLinkedListEntry * Next(VOID) {
|
|
return (CDoubleLinkedListEntry *)m_List.Flink;
|
|
}
|
|
|
|
CDoubleLinkedListEntry * Prev(VOID) {
|
|
return (CDoubleLinkedListEntry *)m_List.Blink;
|
|
}
|
|
|
|
BOOL IsHead(CDoubleLinkedListEntry * pEntry) {
|
|
return pEntry == Head();
|
|
}
|
|
|
|
VOID InsertHead(CDoubleLinkedList * pList) {
|
|
InsertHeadList(&pList->m_List, &m_List);
|
|
}
|
|
|
|
VOID InsertTail(CDoubleLinkedList * pList) {
|
|
InsertTailList(&pList->m_List, &m_List);
|
|
}
|
|
|
|
VOID Remove(VOID) {
|
|
RemoveEntryList(&m_List);
|
|
}
|
|
|
|
CDoubleLinkedListEntry * RemoveHead(VOID) {
|
|
|
|
//
|
|
// APPCOMPAT - (compiler?) for some reason, the line:
|
|
//
|
|
// return (CDoubleLinkedListEntry *)RemoveHeadList(&List);
|
|
//
|
|
// returns the Flink pointer, but doesn't remove it from List
|
|
//
|
|
|
|
PLIST_ENTRY pEntry = RemoveHeadList(&m_List);
|
|
|
|
return (CDoubleLinkedListEntry *)pEntry;
|
|
}
|
|
|
|
CDoubleLinkedListEntry * RemoveTail(VOID) {
|
|
|
|
//
|
|
// APPCOMPAT - see RemoveHead()
|
|
//
|
|
|
|
PLIST_ENTRY pEntry = RemoveTailList(&m_List);
|
|
|
|
return (CDoubleLinkedListEntry *)pEntry;
|
|
}
|
|
|
|
BOOL IsEmpty(VOID) {
|
|
return IsListEmpty(&m_List);
|
|
}
|
|
|
|
CDoubleLinkedListEntry * FindEntry(CDoubleLinkedListEntry * pEntry) {
|
|
for (CDoubleLinkedListEntry * p = Next(); p != Head(); p = p->Next()) {
|
|
if (p == pEntry) {
|
|
return pEntry;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
};
|
|
|
|
//
|
|
// CTimedListEntry/CTimedList
|
|
//
|
|
|
|
#define CTimedList CTimedListEntry
|
|
|
|
class CTimedListEntry : public CDoubleLinkedListEntry {
|
|
|
|
private:
|
|
|
|
DWORD m_dwTimeStamp;
|
|
DWORD m_dwWaitTime;
|
|
|
|
public:
|
|
|
|
CTimedListEntry() {
|
|
}
|
|
|
|
CTimedListEntry(DWORD dwWaitTime) {
|
|
m_dwTimeStamp = GetTickCount();
|
|
m_dwWaitTime = dwWaitTime;
|
|
}
|
|
|
|
VOID Init(VOID) {
|
|
CDoubleLinkedListEntry::Init();
|
|
m_dwTimeStamp = 0;
|
|
m_dwWaitTime = 0;
|
|
}
|
|
|
|
DWORD GetTimeStamp(VOID) const {
|
|
return m_dwTimeStamp;
|
|
}
|
|
|
|
VOID SetTimeStamp(DWORD dwTimeStamp = GetTickCount()) {
|
|
m_dwTimeStamp = dwTimeStamp;
|
|
}
|
|
|
|
DWORD GetWaitTime(VOID) const {
|
|
return m_dwWaitTime;
|
|
}
|
|
|
|
VOID SetWaitTime(DWORD dwWaitTime) {
|
|
m_dwWaitTime = dwWaitTime;
|
|
}
|
|
|
|
VOID SetExpirationTime(DWORD dwWaitTime) {
|
|
SetTimeStamp();
|
|
SetWaitTime(dwWaitTime);
|
|
}
|
|
|
|
BOOL IsTimedOut(DWORD dwTimeNow = GetTickCount()) const {
|
|
return (m_dwWaitTime != INFINITE)
|
|
? (dwTimeNow >= (m_dwTimeStamp + m_dwWaitTime))
|
|
: FALSE;
|
|
}
|
|
|
|
BOOL IsInfiniteTimeout(VOID) const {
|
|
return (m_dwWaitTime == INFINITE);
|
|
}
|
|
|
|
DWORD ExpiryTime(VOID) const {
|
|
return m_dwTimeStamp + m_dwWaitTime;
|
|
}
|
|
|
|
DWORD TimeToWait(DWORD dwTimeNow = GetTickCount()) {
|
|
|
|
DWORD expiryTime = ExpiryTime();
|
|
|
|
return IsInfiniteTimeout()
|
|
? INFINITE
|
|
: ((dwTimeNow >= expiryTime)
|
|
? 0
|
|
: expiryTime - dwTimeNow);
|
|
}
|
|
|
|
//BOOL InsertFront(CDoubleLinkedList * pList) {
|
|
//
|
|
// DWORD dwExpiryTime = ExpiryTime();
|
|
// CTimedListEntry * pEntry;
|
|
//
|
|
// for (pEntry = (CTimedListEntry *)pList->Next();
|
|
// pEntry != (CTimedListEntry *)pList->Head();
|
|
// pEntry = (CTimedListEntry *)pEntry->Next()) {
|
|
// if (dwExpiryTime < pEntry->ExpiryTime()) {
|
|
// break;
|
|
// }
|
|
// }
|
|
// InsertTail(pEntry);
|
|
// return this == pList->Next();
|
|
//}
|
|
|
|
BOOL InsertBack(CDoubleLinkedList * pList) {
|
|
|
|
DWORD dwExpiryTime = ExpiryTime();
|
|
CTimedListEntry * pEntry;
|
|
|
|
for (pEntry = (CTimedListEntry *)pList->Prev();
|
|
pEntry != (CTimedListEntry *)pList->Head();
|
|
pEntry = (CTimedListEntry *)pEntry->Prev()) {
|
|
if (dwExpiryTime >= pEntry->ExpiryTime()) {
|
|
break;
|
|
}
|
|
}
|
|
InsertTail(pEntry);
|
|
return this == pList->Next();
|
|
}
|
|
};
|
|
|
|
//
|
|
// CPrioritizedListEntry
|
|
//
|
|
|
|
class CPrioritizedListEntry : public CDoubleLinkedListEntry {
|
|
|
|
private:
|
|
|
|
LONG m_lPriority;
|
|
|
|
public:
|
|
|
|
CPrioritizedListEntry(LONG lPriority) {
|
|
m_lPriority = lPriority;
|
|
}
|
|
|
|
LONG GetPriority(VOID) const {
|
|
return m_lPriority;
|
|
}
|
|
|
|
VOID SetPriority(LONG lPriority) {
|
|
m_lPriority = lPriority;
|
|
}
|
|
};
|
|
|
|
//
|
|
// CPrioritizedList
|
|
//
|
|
|
|
class CPrioritizedList : public CDoubleLinkedList {
|
|
|
|
//
|
|
// PERF: this really needs to be a btree of list anchors
|
|
//
|
|
|
|
public:
|
|
|
|
VOID
|
|
insert(
|
|
IN CPrioritizedListEntry * pEntry,
|
|
IN LONG lPriority
|
|
) {
|
|
pEntry->SetPriority(lPriority);
|
|
insert(pEntry);
|
|
}
|
|
|
|
VOID
|
|
insert(
|
|
IN CPrioritizedListEntry * pEntry
|
|
) {
|
|
|
|
CPrioritizedListEntry * pCur;
|
|
|
|
for (pCur = (CPrioritizedListEntry *)Next();
|
|
pCur != (CPrioritizedListEntry *)Head();
|
|
pCur = (CPrioritizedListEntry *)pCur->Next()) {
|
|
|
|
if (pCur->GetPriority() < pEntry->GetPriority()) {
|
|
break;
|
|
}
|
|
}
|
|
pEntry->InsertHead((CDoubleLinkedListEntry *)pCur->Prev());
|
|
}
|
|
};
|