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 /* DEFINES *******************************************************************/
19 #define NUMBER_OF_WORKER_THREADS (5)
21 /* TYPES *********************************************************************/
23 /* GLOBALS *******************************************************************/
26 * PURPOSE: Queue of items waiting to be processed at normal priority
28 EX_WORK_QUEUE ExWorkerQueue
[MaximumWorkQueue
];
30 /* FUNCTIONS ****************************************************************/
33 * FUNCTION: Entry point for a worker thread
35 * context = Parameters
37 * NOTE: To kill a worker thread you must queue an item whose callback
38 * calls PsTerminateSystemThread
43 ExpWorkerThreadEntryPoint(IN PVOID Context
)
45 PWORK_QUEUE_ITEM WorkItem
;
46 PLIST_ENTRY QueueEntry
;
47 WORK_QUEUE_TYPE WorkQueueType
;
48 PEX_WORK_QUEUE WorkQueue
;
50 /* Get Queue Type and Worker Queue */
51 WorkQueueType
= (WORK_QUEUE_TYPE
)Context
;
52 WorkQueue
= &ExWorkerQueue
[WorkQueueType
];
57 /* Wait for Something to Happen on the Queue */
58 QueueEntry
= KeRemoveQueue(&WorkQueue
->WorkerQueue
, KernelMode
, NULL
);
60 /* Can't happen since we do a KernelMode wait (and we're a system thread) */
61 ASSERT((NTSTATUS
)QueueEntry
!= STATUS_USER_APC
);
63 /* this should never happen either, since we wait with NULL timeout,
64 * but there's a slight possibility that STATUS_TIMEOUT is returned
65 * at queue rundown in NT (unlikely) -Gunnar
67 ASSERT((NTSTATUS
)QueueEntry
!= STATUS_TIMEOUT
);
69 /* Increment Processed Work Items */
70 InterlockedIncrement((PLONG
)&WorkQueue
->WorkItemsProcessed
);
72 /* Get the Work Item */
73 WorkItem
= CONTAINING_RECORD(QueueEntry
, WORK_QUEUE_ITEM
, List
);
75 /* Call the Worker Routine */
76 WorkItem
->WorkerRoutine(WorkItem
->Parameter
);
78 /* Make sure it returned at right IRQL */
79 if (KeGetCurrentIrql() != PASSIVE_LEVEL
) {
81 /* FIXME: Make this an Ex */
82 KEBUGCHECK(WORKER_THREAD_RETURNED_AT_BAD_IRQL
);
85 /* Make sure it returned with Impersionation Disabled */
86 if (PsGetCurrentThread()->ActiveImpersonationInfo
) {
88 /* FIXME: Make this an Ex */
89 KEBUGCHECK(IMPERSONATING_WORKER_THREAD
);
97 ExpInitializeWorkQueue(WORK_QUEUE_TYPE WorkQueueType
,
104 /* Loop through how many threads we need to create */
105 for (i
= 0; i
< NUMBER_OF_WORKER_THREADS
; i
++) {
107 /* Create the System Thread */
108 PsCreateSystemThread(&hThread
,
113 ExpWorkerThreadEntryPoint
,
114 (PVOID
)WorkQueueType
);
117 ObReferenceObjectByHandle(hThread
,
118 THREAD_SET_INFORMATION
,
124 /* Set the Priority */
125 KeSetPriorityThread(&Thread
->Tcb
, Priority
);
127 /* Dereference and close handle */
128 ObDereferenceObject(Thread
);
136 ExpInitializeWorkerThreads(VOID
)
140 /* Initialize the Array */
141 for (WorkQueueType
= 0; WorkQueueType
< MaximumWorkQueue
; WorkQueueType
++) {
143 RtlZeroMemory(&ExWorkerQueue
[WorkQueueType
], sizeof(EX_WORK_QUEUE
));
144 KeInitializeQueue(&ExWorkerQueue
[WorkQueueType
].WorkerQueue
, 0);
147 /* Create the built-in worker threads for each work queue */
148 ExpInitializeWorkQueue(CriticalWorkQueue
, LOW_REALTIME_PRIORITY
);
149 ExpInitializeWorkQueue(DelayedWorkQueue
, LOW_PRIORITY
);
150 ExpInitializeWorkQueue(HyperCriticalWorkQueue
, HIGH_PRIORITY
);
156 * FUNCTION: Inserts a work item in a queue for one of the system worker
159 * WorkItem = Item to insert
160 * QueueType = Queue to insert it in
164 ExQueueWorkItem(PWORK_QUEUE_ITEM WorkItem
,
165 WORK_QUEUE_TYPE QueueType
)
167 ASSERT(WorkItem
!=NULL
);
168 ASSERT_IRQL(DISPATCH_LEVEL
);
169 ASSERT(WorkItem
->List
.Flink
== NULL
);
171 /* Insert the Queue */
172 KeInsertQueue(&ExWorkerQueue
[QueueType
].WorkerQueue
, &WorkItem
->List
);