2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ex/work.c
5 * PURPOSE: Manage system work queues
7 * PROGRAMMERS: Alex Ionescu - Used correct work queue array and added some fixes and checks.
8 * Gunnar Dalsnes - Implemented
11 /* INCLUDES ******************************************************************/
15 #include <internal/debug.h>
17 #if defined (ALLOC_PRAGMA)
18 #pragma alloc_text(INIT, ExpInitializeWorkerThreads)
21 /* DEFINES *******************************************************************/
23 #define NUMBER_OF_WORKER_THREADS (5)
25 /* TYPES *********************************************************************/
27 /* GLOBALS *******************************************************************/
30 * PURPOSE: Queue of items waiting to be processed at normal priority
32 EX_WORK_QUEUE ExWorkerQueue
[MaximumWorkQueue
];
34 /* FUNCTIONS ****************************************************************/
37 * FUNCTION: Entry point for a worker thread
39 * context = Parameters
41 * NOTE: To kill a worker thread you must queue an item whose callback
42 * calls PsTerminateSystemThread
47 ExpWorkerThreadEntryPoint(IN PVOID Context
)
49 PWORK_QUEUE_ITEM WorkItem
;
50 PLIST_ENTRY QueueEntry
;
51 WORK_QUEUE_TYPE WorkQueueType
;
52 PEX_WORK_QUEUE WorkQueue
;
54 /* Get Queue Type and Worker Queue */
55 WorkQueueType
= (WORK_QUEUE_TYPE
)Context
;
56 WorkQueue
= &ExWorkerQueue
[WorkQueueType
];
61 /* Wait for Something to Happen on the Queue */
62 QueueEntry
= KeRemoveQueue(&WorkQueue
->WorkerQueue
, KernelMode
, NULL
);
64 /* Can't happen since we do a KernelMode wait (and we're a system thread) */
65 ASSERT((NTSTATUS
)QueueEntry
!= STATUS_USER_APC
);
67 /* this should never happen either, since we wait with NULL timeout,
68 * but there's a slight possibility that STATUS_TIMEOUT is returned
69 * at queue rundown in NT (unlikely) -Gunnar
71 ASSERT((NTSTATUS
)QueueEntry
!= STATUS_TIMEOUT
);
73 /* Increment Processed Work Items */
74 InterlockedIncrement((PLONG
)&WorkQueue
->WorkItemsProcessed
);
76 /* Get the Work Item */
77 WorkItem
= CONTAINING_RECORD(QueueEntry
, WORK_QUEUE_ITEM
, List
);
79 /* Call the Worker Routine */
80 WorkItem
->WorkerRoutine(WorkItem
->Parameter
);
82 /* Make sure it returned at right IRQL */
83 if (KeGetCurrentIrql() != PASSIVE_LEVEL
) {
85 KEBUGCHECKEX(WORKER_THREAD_RETURNED_AT_BAD_IRQL
,
86 (ULONG_PTR
)WorkItem
->WorkerRoutine
,
88 (ULONG_PTR
)WorkItem
->Parameter
,
92 /* Make sure it returned with Impersionation Disabled */
93 if (PsGetCurrentThread()->ActiveImpersonationInfo
) {
95 KEBUGCHECKEX(IMPERSONATING_WORKER_THREAD
,
96 (ULONG_PTR
)WorkItem
->WorkerRoutine
,
97 (ULONG_PTR
)WorkItem
->Parameter
,
107 ExpInitializeWorkQueue(WORK_QUEUE_TYPE WorkQueueType
,
114 /* Loop through how many threads we need to create */
115 for (i
= 0; i
< NUMBER_OF_WORKER_THREADS
; i
++) {
117 /* Create the System Thread */
118 PsCreateSystemThread(&hThread
,
123 ExpWorkerThreadEntryPoint
,
124 (PVOID
)WorkQueueType
);
127 ObReferenceObjectByHandle(hThread
,
128 THREAD_SET_INFORMATION
,
134 /* Set the Priority */
135 KeSetPriorityThread(&Thread
->Tcb
, Priority
);
137 /* Dereference and close handle */
138 ObDereferenceObject(Thread
);
146 ExpInitializeWorkerThreads(VOID
)
150 /* Initialize the Array */
151 for (WorkQueueType
= 0; WorkQueueType
< MaximumWorkQueue
; WorkQueueType
++) {
153 RtlZeroMemory(&ExWorkerQueue
[WorkQueueType
], sizeof(EX_WORK_QUEUE
));
154 KeInitializeQueue(&ExWorkerQueue
[WorkQueueType
].WorkerQueue
, 0);
157 /* Create the built-in worker threads for each work queue */
158 ExpInitializeWorkQueue(CriticalWorkQueue
, LOW_REALTIME_PRIORITY
);
159 ExpInitializeWorkQueue(DelayedWorkQueue
, LOW_PRIORITY
);
160 ExpInitializeWorkQueue(HyperCriticalWorkQueue
, HIGH_PRIORITY
);
166 * FUNCTION: Inserts a work item in a queue for one of the system worker
169 * WorkItem = Item to insert
170 * QueueType = Queue to insert it in
174 ExQueueWorkItem(PWORK_QUEUE_ITEM WorkItem
,
175 WORK_QUEUE_TYPE QueueType
)
177 ASSERT(WorkItem
!=NULL
);
178 ASSERT_IRQL(DISPATCH_LEVEL
);
179 ASSERT(WorkItem
->List
.Flink
== NULL
);
181 /* Insert the Queue */
182 KeInsertQueue(&ExWorkerQueue
[QueueType
].WorkerQueue
, &WorkItem
->List
);