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