ff6a24c24ec88ae9828950a71dd076a535e3162e
[reactos.git] / reactos / ntoskrnl / ex / work.c
1 /*
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
6 *
7 * PROGRAMMERS: Alex Ionescu - Used correct work queue array and added some fixes and checks.
8 * Gunnar Dalsnes - Implemented
9 */
10
11 /* INCLUDES ******************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <internal/debug.h>
16
17 /* DEFINES *******************************************************************/
18
19 #define NUMBER_OF_WORKER_THREADS (5)
20
21 /* TYPES *********************************************************************/
22
23 /* GLOBALS *******************************************************************/
24
25 /*
26 * PURPOSE: Queue of items waiting to be processed at normal priority
27 */
28 EX_WORK_QUEUE ExWorkerQueue[MaximumWorkQueue];
29
30 /* FUNCTIONS ****************************************************************/
31
32 /*
33 * FUNCTION: Entry point for a worker thread
34 * ARGUMENTS:
35 * context = Parameters
36 * RETURNS: Status
37 * NOTE: To kill a worker thread you must queue an item whose callback
38 * calls PsTerminateSystemThread
39 */
40 static
41 VOID
42 STDCALL
43 ExpWorkerThreadEntryPoint(IN PVOID Context)
44 {
45 PWORK_QUEUE_ITEM WorkItem;
46 PLIST_ENTRY QueueEntry;
47 WORK_QUEUE_TYPE WorkQueueType;
48 PEX_WORK_QUEUE WorkQueue;
49
50 /* Get Queue Type and Worker Queue */
51 WorkQueueType = (WORK_QUEUE_TYPE)Context;
52 WorkQueue = &ExWorkerQueue[WorkQueueType];
53
54 /* Loop forever */
55 while (TRUE) {
56
57 /* Wait for Something to Happen on the Queue */
58 QueueEntry = KeRemoveQueue(&WorkQueue->WorkerQueue, KernelMode, NULL);
59
60 /* Can't happen since we do a KernelMode wait (and we're a system thread) */
61 ASSERT((NTSTATUS)QueueEntry != STATUS_USER_APC);
62
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
66 */
67 ASSERT((NTSTATUS)QueueEntry != STATUS_TIMEOUT);
68
69 /* Increment Processed Work Items */
70 InterlockedIncrement((PLONG)&WorkQueue->WorkItemsProcessed);
71
72 /* Get the Work Item */
73 WorkItem = CONTAINING_RECORD(QueueEntry, WORK_QUEUE_ITEM, List);
74
75 /* Call the Worker Routine */
76 WorkItem->WorkerRoutine(WorkItem->Parameter);
77
78 /* Make sure it returned at right IRQL */
79 if (KeGetCurrentIrql() != PASSIVE_LEVEL) {
80
81 /* FIXME: Make this an Ex */
82 KEBUGCHECK(WORKER_THREAD_RETURNED_AT_BAD_IRQL);
83 }
84
85 /* Make sure it returned with Impersionation Disabled */
86 if (PsGetCurrentThread()->ActiveImpersonationInfo) {
87
88 /* FIXME: Make this an Ex */
89 KEBUGCHECK(IMPERSONATING_WORKER_THREAD);
90 }
91 }
92 }
93
94 static
95 VOID
96 STDCALL
97 ExpInitializeWorkQueue(WORK_QUEUE_TYPE WorkQueueType,
98 KPRIORITY Priority)
99 {
100 ULONG i;
101 PETHREAD Thread;
102 HANDLE hThread;
103
104 /* Loop through how many threads we need to create */
105 for (i = 0; i < NUMBER_OF_WORKER_THREADS; i++) {
106
107 /* Create the System Thread */
108 PsCreateSystemThread(&hThread,
109 THREAD_ALL_ACCESS,
110 NULL,
111 NULL,
112 NULL,
113 ExpWorkerThreadEntryPoint,
114 (PVOID)WorkQueueType);
115
116 /* Get the Thread */
117 ObReferenceObjectByHandle(hThread,
118 THREAD_SET_INFORMATION,
119 PsThreadType,
120 KernelMode,
121 (PVOID*)&Thread,
122 NULL);
123
124 /* Set the Priority */
125 KeSetPriorityThread(&Thread->Tcb, Priority);
126
127 /* Dereference and close handle */
128 ObDereferenceObject(Thread);
129 ZwClose(hThread);
130 }
131 }
132
133 VOID
134 INIT_FUNCTION
135 STDCALL
136 ExpInitializeWorkerThreads(VOID)
137 {
138 ULONG WorkQueueType;
139
140 /* Initialize the Array */
141 for (WorkQueueType = 0; WorkQueueType < MaximumWorkQueue; WorkQueueType++) {
142
143 RtlZeroMemory(&ExWorkerQueue[WorkQueueType], sizeof(EX_WORK_QUEUE));
144 KeInitializeQueue(&ExWorkerQueue[WorkQueueType].WorkerQueue, 0);
145 }
146
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);
151 }
152
153 /*
154 * @implemented
155 *
156 * FUNCTION: Inserts a work item in a queue for one of the system worker
157 * threads to process
158 * ARGUMENTS:
159 * WorkItem = Item to insert
160 * QueueType = Queue to insert it in
161 */
162 VOID
163 STDCALL
164 ExQueueWorkItem(PWORK_QUEUE_ITEM WorkItem,
165 WORK_QUEUE_TYPE QueueType)
166 {
167 ASSERT(WorkItem!=NULL);
168 ASSERT_IRQL(DISPATCH_LEVEL);
169 ASSERT(WorkItem->List.Flink == NULL);
170
171 /* Insert the Queue */
172 KeInsertQueue(&ExWorkerQueue[QueueType].WorkerQueue, &WorkItem->List);
173 }
174
175 /* EOF */