Copy wininet to branch
[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(&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 ExpInitializeWorkerThreads(VOID)
136 {
137 ULONG WorkQueueType;
138
139 /* Initialize the Array */
140 for (WorkQueueType = 0; WorkQueueType < MaximumWorkQueue; WorkQueueType++) {
141
142 RtlZeroMemory(&ExWorkerQueue[WorkQueueType], sizeof(EX_WORK_QUEUE));
143 KeInitializeQueue(&ExWorkerQueue[WorkQueueType].WorkerQueue, 0);
144 }
145
146 /* Create the built-in worker threads for each work queue */
147 ExpInitializeWorkQueue(CriticalWorkQueue, LOW_REALTIME_PRIORITY);
148 ExpInitializeWorkQueue(DelayedWorkQueue, LOW_PRIORITY);
149 ExpInitializeWorkQueue(HyperCriticalWorkQueue, HIGH_PRIORITY);
150 }
151
152 /*
153 * @implemented
154 *
155 * FUNCTION: Inserts a work item in a queue for one of the system worker
156 * threads to process
157 * ARGUMENTS:
158 * WorkItem = Item to insert
159 * QueueType = Queue to insert it in
160 */
161 VOID
162 STDCALL
163 ExQueueWorkItem(PWORK_QUEUE_ITEM WorkItem,
164 WORK_QUEUE_TYPE QueueType)
165 {
166 ASSERT(WorkItem!=NULL);
167 ASSERT_IRQL(DISPATCH_LEVEL);
168 ASSERT(WorkItem->List.Flink == NULL);
169
170 /* Insert the Queue */
171 KeInsertQueue(&ExWorkerQueue[QueueType].WorkerQueue, &WorkItem->List);
172 }
173
174 /* EOF */