|
|
/*++
Copyright (c) 1998-2002 Microsoft Corporation
Module Name:
thrdpoolp.h
Abstract:
This module contains private declarations for the thread pool package.
Author:
Keith Moore (KeithMo) 10-Jun-1998
Revision History:
Chun Ye (ChunYe) Spring 2001 George V. Reilly (GeorgeRe) Summer 2001
--*/
#ifndef _THRDPOOLP_H_
#define _THRDPOOLP_H_
//
// CODEWORK: Build a new kind of tracelog for threadpool. Reftrace is
// inadequate.
//
// Special threads
enum { WaitThreadPool, HighPriorityThreadPool, MaxThreadPools // must be last
};
//
// Various states that a thread pool worker thread can be in
//
typedef enum { ThreadPoolCreated = 1, ThreadPoolInit, ThreadPoolFlush, ThreadPoolSearchOther, ThreadPoolBlock, ThreadPoolReverseList, ThreadPoolExecute, ThreadPoolException, ThreadPoolTerminated, } UL_THREAD_POOL_STATE;
typedef struct _UL_THREAD_POOL *PUL_THREAD_POOL;
//
// Thread tracker object. One of these objects is created for each
// thread in the pool. These are useful for (among other things)
// debugging.
//
typedef struct _UL_THREAD_TRACKER { //
// Links onto the per-thread-pool list.
//
LIST_ENTRY ThreadListEntry;
//
// Back pointer to owning threadpool
//
PUL_THREAD_POOL pThreadPool;
//
// The thread.
//
PETHREAD pThread;
//
// The thread handle returned from PsCreateSystemThread.
//
HANDLE ThreadHandle;
//
// List of worker items currently being processed in inner loop
// and length of that list
//
SLIST_ENTRY CurrentListHead; ULONG ListLength;
//
// Current state of the thread
//
UL_THREAD_POOL_STATE State;
//
// Current workitem and current workroutine
//
PUL_WORK_ROUTINE pWorkRoutine; PUL_WORK_ITEM pWorkItem;
//
// Statistics
// Average queue length (at time of flush) = SumQueueLength / QueueFlushes
//
ULONGLONG Executions; ULONGLONG SumQueueLengths; ULONG QueueFlushes; ULONG MaxQueueLength;
} UL_THREAD_TRACKER, *PUL_THREAD_TRACKER;
//
// The thread pool object.
//
typedef struct _UL_THREAD_POOL { //
// List of unprocessed worker items on this thread pool.
//
SLIST_HEADER WorkQueueSList;
//
// An event used to wakeup the thread from blocking state.
//
KEVENT WorkQueueEvent;
//
// List of threads.
//
LIST_ENTRY ThreadListHead;
//
// Pointer to the special thread designated as the IRP thread. The
// IRP thread is the first pool thread created and the last one to
// die. It is also the target for all asynchronous IRPs.
//
PETHREAD pIrpThread;
//
// A very infrequently used spinlock.
//
UL_SPIN_LOCK ThreadSpinLock;
//
// The number of threads we created for this pool.
//
UCHAR ThreadCount;
//
// Flag used to indicate that this pool has been successfully
// initialized.
//
BOOLEAN Initialized;
//
// Target CPU for this pool. The worker threads use this to set
// their hard affinity.
//
UCHAR ThreadCpu;
//
// Regular worker threads can pull workitems from
// other regular queues on other processors.
//
BOOLEAN LookOnOtherQueues;
} UL_THREAD_POOL, *PUL_THREAD_POOL;
//
// Necessary to ensure our array of UL_THREAD_POOL structures is
// cache aligned.
//
typedef union _UL_ALIGNED_THREAD_POOL { UL_THREAD_POOL ThreadPool;
UCHAR CacheAlignment[(sizeof(UL_THREAD_POOL) + UL_CACHE_LINE - 1) & ~(UL_CACHE_LINE - 1)];
} UL_ALIGNED_THREAD_POOL;
//
// Inline function to validate that a UL_WORK_ITEM has been properly
// initialized. Bugcheck if it's not.
//
__inline VOID UlpValidateWorkItem( IN PUL_WORK_ITEM pWorkItem, IN PCSTR pFileName, IN USHORT LineNumber ) { if (! UlIsInitializedWorkItem(pWorkItem)) { ASSERT(! "Uninitialized workitem");
//
// If the workitem was not properly zeroed, then chances are that
// it's already on a work queue. If we were to requeue the work item,
// it would corrupt the work queue. Better to fail hard now, while
// there's some hope of figuring out what went wrong, than let it
// crash mysteriously later.
//
UlBugCheckEx( HTTP_SYS_BUGCHECK_WORKITEM, (ULONG_PTR) pWorkItem, (ULONG_PTR) pFileName, (ULONG_PTR) LineNumber ); } } // UlpValidateWorkItem
//
// Inline function to queue a preinitialized UL_WORK_ITEM.
//
__inline VOID QUEUE_UL_WORK_ITEM( PUL_THREAD_POOL pThreadPool, IN PUL_WORK_ITEM pWorkItem ) { if (NULL == InterlockedPushEntrySList( &pThreadPool->WorkQueueSList, &pWorkItem->QueueListEntry )) { //
// If the work queue was empty when we added this item,
// set the event to wake the thread up
//
KeSetEvent( &pThreadPool->WorkQueueEvent, 0, FALSE ); }
}
//
// Private prototypes.
//
NTSTATUS UlpCreatePoolThread( IN PUL_THREAD_POOL pThreadPool );
VOID UlpThreadPoolWorker( IN PVOID Context );
VOID UlpInitThreadTracker( IN PUL_THREAD_POOL pThreadPool, IN PETHREAD pThread, IN PUL_THREAD_TRACKER pThreadTracker );
VOID UlpDestroyThreadTracker( IN PUL_THREAD_TRACKER pThreadTracker );
PUL_THREAD_TRACKER UlpPopThreadTracker( IN PUL_THREAD_POOL pThreadPool );
VOID UlpKillThreadWorker( IN PUL_WORK_ITEM pWorkItem );
//
// Private globals.
//
extern DECLSPEC_ALIGN(UL_CACHE_LINE) UL_ALIGNED_THREAD_POOL g_UlThreadPool[];
#define CURRENT_THREAD_POOL() \
&g_UlThreadPool[KeGetCurrentProcessorNumber()].ThreadPool
#define CURRENT_SYNC_THREAD_POOL() \
&g_UlThreadPool[g_UlNumberOfProcessors + KeGetCurrentProcessorNumber()].ThreadPool
#define WAIT_THREAD_POOL() \
&g_UlThreadPool[(g_UlNumberOfProcessors * 2) + WaitThreadPool].ThreadPool
#define HIGH_PRIORITY_THREAD_POOL() \
&g_UlThreadPool[(g_UlNumberOfProcessors * 2) + HighPriorityThreadPool].ThreadPool
extern PUL_WORK_ITEM g_pKillerWorkItems;
#endif // _THRDPOOLP_H_
|