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