Shutdown the process manager before shutdown the registry.
[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 KEBUGCHECKEX(WORKER_THREAD_RETURNED_AT_BAD_IRQL,
82 (ULONG_PTR)WorkItem->WorkerRoutine,
83 KeGetCurrentIrql(),
84 (ULONG_PTR)WorkItem->Parameter,
85 (ULONG_PTR)WorkItem);
86 }
87
88 /* Make sure it returned with Impersionation Disabled */
89 if (PsGetCurrentThread()->ActiveImpersonationInfo) {
90
91 KEBUGCHECKEX(IMPERSONATING_WORKER_THREAD,
92 (ULONG_PTR)WorkItem->WorkerRoutine,
93 (ULONG_PTR)WorkItem->Parameter,
94 (ULONG_PTR)WorkItem,
95 0);
96 }
97 }
98 }
99
100 static
101 VOID
102 STDCALL
103 ExpInitializeWorkQueue(WORK_QUEUE_TYPE WorkQueueType,
104 KPRIORITY Priority)
105 {
106 ULONG i;
107 PETHREAD Thread;
108 HANDLE hThread;
109
110 /* Loop through how many threads we need to create */
111 for (i = 0; i < NUMBER_OF_WORKER_THREADS; i++) {
112
113 /* Create the System Thread */
114 PsCreateSystemThread(&hThread,
115 THREAD_ALL_ACCESS,
116 NULL,
117 NULL,
118 NULL,
119 ExpWorkerThreadEntryPoint,
120 (PVOID)WorkQueueType);
121
122 /* Get the Thread */
123 ObReferenceObjectByHandle(hThread,
124 THREAD_SET_INFORMATION,
125 PsThreadType,
126 KernelMode,
127 (PVOID*)&Thread,
128 NULL);
129
130 /* Set the Priority */
131 KeSetPriorityThread(&Thread->Tcb, Priority);
132
133 /* Dereference and close handle */
134 ObDereferenceObject(Thread);
135 ZwClose(hThread);
136 }
137 }
138
139 VOID
140 INIT_FUNCTION
141 STDCALL
142 ExpInitializeWorkerThreads(VOID)
143 {
144 ULONG WorkQueueType;
145
146 /* Initialize the Array */
147 for (WorkQueueType = 0; WorkQueueType < MaximumWorkQueue; WorkQueueType++) {
148
149 RtlZeroMemory(&ExWorkerQueue[WorkQueueType], sizeof(EX_WORK_QUEUE));
150 KeInitializeQueue(&ExWorkerQueue[WorkQueueType].WorkerQueue, 0);
151 }
152
153 /* Create the built-in worker threads for each work queue */
154 ExpInitializeWorkQueue(CriticalWorkQueue, LOW_REALTIME_PRIORITY);
155 ExpInitializeWorkQueue(DelayedWorkQueue, LOW_PRIORITY);
156 ExpInitializeWorkQueue(HyperCriticalWorkQueue, HIGH_PRIORITY);
157 }
158
159 /*
160 * @implemented
161 *
162 * FUNCTION: Inserts a work item in a queue for one of the system worker
163 * threads to process
164 * ARGUMENTS:
165 * WorkItem = Item to insert
166 * QueueType = Queue to insert it in
167 */
168 VOID
169 STDCALL
170 ExQueueWorkItem(PWORK_QUEUE_ITEM WorkItem,
171 WORK_QUEUE_TYPE QueueType)
172 {
173 ASSERT(WorkItem!=NULL);
174 ASSERT_IRQL(DISPATCH_LEVEL);
175 ASSERT(WorkItem->List.Flink == NULL);
176
177 /* Insert the Queue */
178 KeInsertQueue(&ExWorkerQueue[QueueType].WorkerQueue, &WorkItem->List);
179 }
180
181 /* EOF */