3c07d0de9b5d187a02c4ec45ac3723783cf3f657
[reactos.git] / reactos / ntoskrnl / ex / work.c
1 /* $Id: work.c,v 1.9 2000/10/07 13:41:50 dwelch Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: mkernel/kernel/work.c
6 * PURPOSE: Manage system work queues
7 * PROGRAMMER: David Welch (welch@mcmail.com)
8 * REVISION HISTORY:
9 * 29/06/98: Created
10 */
11
12 /* INCLUDES ******************************************************************/
13
14 #include <ddk/ntddk.h>
15
16 #include <internal/ps.h>
17
18 #include <internal/debug.h>
19
20 /* DEFINES *******************************************************************/
21
22 #define NUMBER_OF_WORKER_THREADS (5)
23
24 /* TYPES *********************************************************************/
25
26 typedef struct _WORK_QUEUE
27 {
28 /*
29 * PURPOSE: Head of the list of waiting work items
30 */
31 LIST_ENTRY Head;
32
33 /*
34 * PURPOSE: Sychronize access to the work queue
35 */
36 KSPIN_LOCK Lock;
37
38 /*
39 * PURPOSE: Worker threads with nothing to do wait on this event
40 */
41 KSEMAPHORE Sem;
42
43 /*
44 * PURPOSE: Thread associated with work queue
45 */
46 HANDLE Thread[NUMBER_OF_WORKER_THREADS];
47 } WORK_QUEUE, *PWORK_QUEUE;
48
49 /* GLOBALS *******************************************************************/
50
51 /*
52 * PURPOSE: Queue of items waiting to be processed at normal priority
53 */
54 WORK_QUEUE EiNormalWorkQueue;
55
56 WORK_QUEUE EiCriticalWorkQueue;
57
58 WORK_QUEUE EiHyperCriticalWorkQueue;
59
60 /* FUNCTIONS ****************************************************************/
61
62 static NTSTATUS ExWorkerThreadEntryPoint(PVOID context)
63 /*
64 * FUNCTION: Entry point for a worker thread
65 * ARGUMENTS:
66 * context = Parameters
67 * RETURNS: Status
68 * NOTE: To kill a worker thread you must queue an item whose callback
69 * calls PsTerminateSystemThread
70 */
71 {
72 PWORK_QUEUE queue = (PWORK_QUEUE)context;
73 PWORK_QUEUE_ITEM item;
74 PLIST_ENTRY current;
75
76 for(;;)
77 {
78 current = ExInterlockedRemoveHeadList(&queue->Head,
79 &queue->Lock);
80 if (current!=NULL)
81 {
82 item = CONTAINING_RECORD(current,WORK_QUEUE_ITEM,Entry);
83 item->Routine(item->Context);
84 }
85 else
86 {
87 KeWaitForSingleObject((PVOID)&queue->Sem,
88 Executive,
89 KernelMode,
90 FALSE,
91 NULL);
92 DPRINT1("Woke from wait\n");
93 }
94 }
95 }
96
97 static VOID ExInitializeWorkQueue(PWORK_QUEUE WorkQueue,
98 KPRIORITY Priority)
99 {
100 ULONG i;
101 PETHREAD Thread;
102
103 InitializeListHead(&WorkQueue->Head);
104 KeInitializeSpinLock(&WorkQueue->Lock);
105 KeInitializeSemaphore(&WorkQueue->Sem,
106 0,
107 256);
108 for (i=0; i<NUMBER_OF_WORKER_THREADS; i++)
109 {
110 PsCreateSystemThread(&WorkQueue->Thread[i],
111 THREAD_ALL_ACCESS,
112 NULL,
113 NULL,
114 NULL,
115 ExWorkerThreadEntryPoint,
116 WorkQueue);
117 ObReferenceObjectByHandle(WorkQueue->Thread[i],
118 THREAD_ALL_ACCESS,
119 PsThreadType,
120 KernelMode,
121 (PVOID*)&Thread,
122 NULL);
123 KeSetPriorityThread(&Thread->Tcb,
124 Priority);
125 ObDereferenceObject(Thread);
126 }
127 }
128
129 VOID ExInitializeWorkerThreads(VOID)
130 {
131 ExInitializeWorkQueue(&EiNormalWorkQueue,
132 LOW_PRIORITY);
133 ExInitializeWorkQueue(&EiCriticalWorkQueue,
134 LOW_REALTIME_PRIORITY);
135 ExInitializeWorkQueue(&EiHyperCriticalWorkQueue,
136 HIGH_PRIORITY);
137 }
138
139 VOID STDCALL
140 ExQueueWorkItem (PWORK_QUEUE_ITEM WorkItem,
141 WORK_QUEUE_TYPE QueueType)
142 /*
143 * FUNCTION: Inserts a work item in a queue for one of the system worker
144 * threads to process
145 * ARGUMENTS:
146 * WorkItem = Item to insert
147 * QueueType = Queue to insert it in
148 */
149 {
150 assert(WorkItem!=NULL);
151 ASSERT_IRQL(DISPATCH_LEVEL);
152
153 /*
154 * Insert the item in the appropiate queue and wake up any thread
155 * waiting for something to do
156 */
157 switch(QueueType)
158 {
159 case DelayedWorkQueue:
160 ExInterlockedInsertTailList(&EiNormalWorkQueue.Head,
161 &WorkItem->Entry,
162 &EiNormalWorkQueue.Lock);
163 KeReleaseSemaphore(&EiNormalWorkQueue.Sem,
164 IO_NO_INCREMENT,
165 1,
166 FALSE);
167 break;
168
169 case CriticalWorkQueue:
170 ExInterlockedInsertTailList(&EiCriticalWorkQueue.Head,
171 &WorkItem->Entry,
172 &EiCriticalWorkQueue.Lock);
173 KeReleaseSemaphore(&EiCriticalWorkQueue.Sem,
174 IO_NO_INCREMENT,
175 1,
176 FALSE);
177 break;
178
179 case HyperCriticalWorkQueue:
180 ExInterlockedInsertTailList(&EiHyperCriticalWorkQueue.Head,
181 &WorkItem->Entry,
182 &EiHyperCriticalWorkQueue.Lock);
183 KeReleaseSemaphore(&EiHyperCriticalWorkQueue.Sem,
184 IO_NO_INCREMENT,
185 1,
186 FALSE);
187 break;
188
189 }
190 }
191
192 /* EOF */