+FSCTL_DISMOUNT_VOLUME define
[reactos.git] / ntoskrnl / ke / dpc.c
1 /*
2  *  ReactOS kernel
3  *  Copyright (C) 2000, 1999, 1998 David Welch <welch@cwcom.net>, 
4  *                                 Philip Susi <phreak@iag.net>,
5  *                                 Eric Kohl <ekohl@abo.rhein-zeitung.de>
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21 /* $Id$
22  *
23  * COPYRIGHT:       See COPYING in the top level directory
24  * PROJECT:         ReactOS kernel
25  * FILE:            ntoskrnl/ke/dpc.c
26  * PURPOSE:         Handle DPCs (Delayed Procedure Calls)
27  * PROGRAMMER:      David Welch (welch@mcmail.com)
28  * UPDATE HISTORY:
29  *                28/05/98: Created
30  *                12/3/99:  Phillip Susi: Fixed IRQL problem
31  */
32
33 /*
34  * NOTE: See also the higher level support routines in ntoskrnl/io/dpc.c
35  */
36
37 /* INCLUDES ***************************************************************/
38
39 #include <ddk/ntddk.h>
40 #include <internal/ps.h>
41
42 #define NDEBUG
43 #include <internal/debug.h>
44
45 /* TYPES *******************************************************************/
46
47 /* GLOBALS ******************************************************************/
48
49 #ifndef LIBCAPTIVE
50
51 static LIST_ENTRY DpcQueueHead; /* Head of the list of pending DPCs */
52 #endif /* LIBCAPTIVE */
53 static KSPIN_LOCK DpcQueueLock; /* Lock for the above list */
54 /* 
55  * Number of pending DPCs. This is inspected by
56  * the idle thread to determine if the queue needs to
57  * be run down
58  */
59 ULONG DpcQueueSize = 0; 
60
61 /* FUNCTIONS ****************************************************************/
62
63 VOID STDCALL 
64 KeInitializeDpc (PKDPC                  Dpc,
65                  PKDEFERRED_ROUTINE     DeferredRoutine,
66                  PVOID                  DeferredContext)
67 /*
68  * FUNCTION: Initalizes a DPC
69  * ARGUMENTS:
70  *          Dpc = Caller supplied DPC to be initialized
71  *          DeferredRoutine = Associated DPC callback
72  *          DeferredContext = Parameter to be passed to the callback
73  * NOTE: Callers must be running at IRQL PASSIVE_LEVEL
74  */
75 {
76    Dpc->Type = 0;
77    Dpc->DeferredRoutine = DeferredRoutine;
78    Dpc->DeferredContext = DeferredContext;
79    Dpc->Lock = 0;
80 }
81
82 #ifndef LIBCAPTIVE
83
84 VOID STDCALL 
85 KiDispatchInterrupt(VOID)
86 /*
87  * FUNCTION: Called to execute queued dpcs
88  */
89 {
90    PLIST_ENTRY current_entry;
91    PKDPC current;
92    KIRQL oldlvl;
93    
94    assert_irql(DISPATCH_LEVEL);
95    
96    if (DpcQueueSize == 0)
97      {
98         return;
99      }
100    
101    KeRaiseIrql(HIGH_LEVEL, &oldlvl);
102    KeAcquireSpinLockAtDpcLevel(&DpcQueueLock);
103    current_entry = RemoveHeadList(&DpcQueueHead);
104    if (current_entry != &DpcQueueHead)
105      {
106        DpcQueueSize--;
107      }
108    KeReleaseSpinLockFromDpcLevel(&DpcQueueLock);
109    current = CONTAINING_RECORD(current_entry,KDPC,DpcListEntry);
110    current->Lock=FALSE;
111    KeLowerIrql(oldlvl);
112    while (current_entry!=(&DpcQueueHead))
113      {
114         current->DeferredRoutine(current,current->DeferredContext,
115                                  current->SystemArgument1,
116                                  current->SystemArgument2);
117
118         KeRaiseIrql(HIGH_LEVEL, &oldlvl);
119         KeAcquireSpinLockAtDpcLevel(&DpcQueueLock);
120         current_entry = RemoveHeadList(&DpcQueueHead);
121         if (current_entry != &DpcQueueHead)
122           {
123             DpcQueueSize--;
124           }
125         KeReleaseSpinLockFromDpcLevel(&DpcQueueLock);
126         current = CONTAINING_RECORD(current_entry,KDPC,DpcListEntry);
127         current->Lock=FALSE;
128         KeLowerIrql(oldlvl);
129      }
130 }
131
132 #endif /* LIBCAPTIVE */
133
134 BOOLEAN STDCALL 
135 KeRemoveQueueDpc (PKDPC Dpc)
136 /*
137  * FUNCTION: Removes DPC object from the system dpc queue
138  * ARGUMENTS:
139  *          Dpc = DPC to remove
140  * RETURNS: TRUE if the DPC was in the queue
141  *          FALSE otherwise
142  */
143 {
144    KIRQL oldIrql;
145    
146    KeAcquireSpinLockAtDpcLevel(&DpcQueueLock);
147    KeRaiseIrql(HIGH_LEVEL, &oldIrql);
148    if (!Dpc->Lock)
149      {
150         KeReleaseSpinLock(&DpcQueueLock, oldIrql);
151         return(FALSE);
152      }
153    RemoveEntryList(&Dpc->DpcListEntry);
154    DpcQueueSize--;
155    Dpc->Lock=0;
156    KeReleaseSpinLock(&DpcQueueLock, oldIrql);
157    return(TRUE);
158 }
159
160 #ifndef LIBCAPTIVE
161
162 BOOLEAN STDCALL 
163 KeInsertQueueDpc (PKDPC Dpc,
164                   PVOID SystemArgument1,
165                   PVOID SystemArgument2)
166 /*
167  * FUNCTION: Queues a DPC for execution when the IRQL of a processor
168  * drops below DISPATCH_LEVEL
169  * ARGUMENTS:
170  *          Dpc = Initalizes DPC
171  *          SystemArguments[1-2] = Undocumented
172  * RETURNS: TRUE if the DPC object wasn't already in the queue
173  *          FALSE otherwise
174  */
175 {
176    KIRQL oldlvl;
177    DPRINT("KeInsertQueueDpc(dpc %x, SystemArgument1 %x, SystemArgument2 %x)\n",
178           Dpc, SystemArgument1, SystemArgument2);
179
180    assert(KeGetCurrentIrql()>=DISPATCH_LEVEL);
181
182    Dpc->Number=0;
183    Dpc->Importance=MediumImportance;
184    Dpc->SystemArgument1=SystemArgument1;
185    Dpc->SystemArgument2=SystemArgument2;
186    if (Dpc->Lock)
187      {
188         return(FALSE);
189      }
190    KeRaiseIrql(HIGH_LEVEL, &oldlvl);
191    KeAcquireSpinLockAtDpcLevel(&DpcQueueLock);
192    InsertHeadList(&DpcQueueHead,&Dpc->DpcListEntry);
193    DPRINT("Dpc->DpcListEntry.Flink %x\n", Dpc->DpcListEntry.Flink);
194    DpcQueueSize++;
195    Dpc->Lock=(PULONG)1;
196    KeReleaseSpinLock( &DpcQueueLock, oldlvl );
197    DPRINT("DpcQueueHead.Flink %x\n",DpcQueueHead.Flink);
198    DPRINT("Leaving KeInsertQueueDpc()\n",0);
199    return(TRUE);
200 }
201
202 /*
203  * FUNCTION: Specifies the DPCs importance
204  * ARGUMENTS:
205  *          Dpc = Initalizes DPC
206  *          Importance = DPC importance
207  * RETURNS: None
208  */
209 VOID STDCALL
210 KeSetImportanceDpc (IN  PKDPC           Dpc,
211                     IN  KDPC_IMPORTANCE Importance)
212 {
213         Dpc->Importance = Importance;
214 }
215
216 /*
217  * FUNCTION: Specifies on which processor the DPC will run
218  * ARGUMENTS:
219  *          Dpc = Initalizes DPC
220  *          Number = Processor number
221  * RETURNS: None
222  */
223 VOID STDCALL
224 KeSetTargetProcessorDpc (IN     PKDPC   Dpc,
225                          IN     CCHAR   Number)
226 {
227         UNIMPLEMENTED;
228 }
229
230 VOID 
231 KeInitDpc(VOID)
232 /*
233  * FUNCTION: Initialize DPC handling
234  */
235 {
236    InitializeListHead(&DpcQueueHead);
237    KeInitializeSpinLock(&DpcQueueLock);
238 }
239
240 #endif /* LIBCAPTIVE */
241
242 /* EOF */