- Change ULONG to ULONG_PTR for StackLimit.
[reactos.git] / reactos / 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: dpc.c,v 1.41 2004/10/30 23:48:56 navaraf Exp $
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 <ntoskrnl.h>
40 #define NDEBUG
41 #include <internal/debug.h>
42
43 /* TYPES *******************************************************************/
44
45 /* GLOBALS ******************************************************************/
46
47 /* FUNCTIONS ****************************************************************/
48
49 /*
50 * @implemented
51 */
52 VOID STDCALL
53 KeInitializeDpc (PKDPC Dpc,
54 PKDEFERRED_ROUTINE DeferredRoutine,
55 PVOID DeferredContext)
56 /*
57 * FUNCTION: Initalizes a DPC
58 * ARGUMENTS:
59 * Dpc = Caller supplied DPC to be initialized
60 * DeferredRoutine = Associated DPC callback
61 * DeferredContext = Parameter to be passed to the callback
62 * NOTE: Callers must be running at IRQL PASSIVE_LEVEL
63 */
64 {
65 Dpc->Type = 0;
66 Dpc->DeferredRoutine = DeferredRoutine;
67 Dpc->DeferredContext = DeferredContext;
68 Dpc->Lock = 0;
69 }
70
71 /*
72 * @implemented
73 */
74 VOID STDCALL
75 KiDispatchInterrupt(VOID)
76 /*
77 * FUNCTION: Called to execute queued dpcs
78 */
79 {
80 PLIST_ENTRY current_entry;
81 PKDPC current;
82 KIRQL oldlvl;
83 PKPCR Pcr;
84 PKTHREAD CurrentThread;
85 PKPROCESS CurrentProcess;
86
87 ASSERT_IRQL(DISPATCH_LEVEL);
88
89 Pcr = KeGetCurrentKPCR();
90
91 if (Pcr->PrcbData.QuantumEnd)
92 {
93 /*
94 * FIXME: Various special cases should be handled here. The scripts
95 * from David B. Probert that describe it under KiQuantumEnd.
96 */
97 CurrentThread = /* Pcr->PcrbData.CurrentThread */ KeGetCurrentThread();
98 CurrentProcess = CurrentThread->ApcState.Process;
99 CurrentThread->Quantum = CurrentProcess->ThreadQuantum;
100 Pcr->PrcbData.QuantumEnd = FALSE;
101 PsDispatchThread(THREAD_STATE_READY);
102 return;
103 }
104
105 if (Pcr->PrcbData.DpcData[0].DpcQueueDepth == 0)
106 {
107 return;
108 }
109
110 KeRaiseIrql(HIGH_LEVEL, &oldlvl);
111 KiAcquireSpinLock(&Pcr->PrcbData.DpcData[0].DpcLock);
112
113 while (!IsListEmpty(&Pcr->PrcbData.DpcData[0].DpcListHead))
114 {
115 ASSERT(Pcr->PrcbData.DpcData[0].DpcQueueDepth > 0);
116
117 current_entry = RemoveHeadList(&Pcr->PrcbData.DpcData[0].DpcListHead);
118 Pcr->PrcbData.DpcData[0].DpcQueueDepth--;
119 Pcr->PrcbData.DpcData[0].DpcCount++;
120
121 ASSERT((Pcr->PrcbData.DpcData[0].DpcQueueDepth == 0 && IsListEmpty(&Pcr->PrcbData.DpcData[0].DpcListHead)) ||
122 (Pcr->PrcbData.DpcData[0].DpcQueueDepth > 0 && !IsListEmpty(&Pcr->PrcbData.DpcData[0].DpcListHead)));
123
124 current = CONTAINING_RECORD(current_entry,KDPC,DpcListEntry);
125 current->Lock=FALSE;
126 Pcr->PrcbData.DpcRoutineActive = 1;
127 KiReleaseSpinLock(&Pcr->PrcbData.DpcData[0].DpcLock);
128 KeLowerIrql(oldlvl);
129 current->DeferredRoutine(current,current->DeferredContext,
130 current->SystemArgument1,
131 current->SystemArgument2);
132
133 KeRaiseIrql(HIGH_LEVEL, &oldlvl);
134 KiAcquireSpinLock(&Pcr->PrcbData.DpcData[0].DpcLock);
135 Pcr->PrcbData.DpcRoutineActive = 0;
136 }
137
138 KiReleaseSpinLock(&Pcr->PrcbData.DpcData[0].DpcLock);
139 KeLowerIrql(oldlvl);
140 }
141
142 /*
143 * @unimplemented
144 */
145 VOID
146 STDCALL
147 KeFlushQueuedDpcs(
148 VOID
149 )
150 {
151 UNIMPLEMENTED;
152 }
153
154 /*
155 * @implemented
156 */
157 BOOLEAN
158 STDCALL
159 KeIsExecutingDpc(
160 VOID
161 )
162 {
163 return KeGetCurrentKPCR()->PrcbData.DpcRoutineActive;
164 }
165
166 /*
167 * @implemented
168 */
169 BOOLEAN STDCALL
170 KeRemoveQueueDpc (PKDPC Dpc)
171 /*
172 * FUNCTION: Removes DPC object from the system dpc queue
173 * ARGUMENTS:
174 * Dpc = DPC to remove
175 * RETURNS: TRUE if the DPC was in the queue
176 * FALSE otherwise
177 */
178 {
179 KIRQL oldIrql;
180 BOOLEAN WasInQueue;
181 PKPCR Pcr;
182
183 Pcr = KeGetCurrentKPCR();
184
185 KeRaiseIrql(HIGH_LEVEL, &oldIrql);
186 KiAcquireSpinLock(&Pcr->PrcbData.DpcData[0].DpcLock);
187 WasInQueue = Dpc->Lock ? TRUE : FALSE;
188 if (WasInQueue)
189 {
190 RemoveEntryList(&Dpc->DpcListEntry);
191 Pcr->PrcbData.DpcData[0].DpcQueueDepth--;
192 Dpc->Lock=0;
193 }
194
195 ASSERT((Pcr->PrcbData.DpcData[0].DpcQueueDepth == 0 && IsListEmpty(&Pcr->PrcbData.DpcData[0].DpcListHead)) ||
196 (Pcr->PrcbData.DpcData[0].DpcQueueDepth > 0 && !IsListEmpty(&Pcr->PrcbData.DpcData[0].DpcListHead)));
197
198 KiReleaseSpinLock(&Pcr->PrcbData.DpcData[0].DpcLock);
199 KeLowerIrql(oldIrql);
200
201 return WasInQueue;
202 }
203
204 /*
205 * @implemented
206 */
207 BOOLEAN STDCALL
208 KeInsertQueueDpc (PKDPC Dpc,
209 PVOID SystemArgument1,
210 PVOID SystemArgument2)
211 /*
212 * FUNCTION: Queues a DPC for execution when the IRQL of a processor
213 * drops below DISPATCH_LEVEL
214 * ARGUMENTS:
215 * Dpc = Initalizes DPC
216 * SystemArguments[1-2] = Undocumented
217 * RETURNS: TRUE if the DPC object wasn't already in the queue
218 * FALSE otherwise
219 */
220 {
221 KIRQL oldlvl;
222 PKPCR Pcr;
223
224 DPRINT("KeInsertQueueDpc(dpc %x, SystemArgument1 %x, SystemArgument2 %x)\n",
225 Dpc, SystemArgument1, SystemArgument2);
226
227 ASSERT(KeGetCurrentIrql()>=DISPATCH_LEVEL);
228
229 Dpc->Number=0;
230 Dpc->Importance=MediumImportance;
231 Dpc->SystemArgument1=SystemArgument1;
232 Dpc->SystemArgument2=SystemArgument2;
233 if (Dpc->Lock)
234 {
235 return(FALSE);
236 }
237
238 Pcr = KeGetCurrentKPCR();
239 KeRaiseIrql(HIGH_LEVEL, &oldlvl);
240 KiAcquireSpinLock(&Pcr->PrcbData.DpcData[0].DpcLock);
241 ASSERT((Pcr->PrcbData.DpcData[0].DpcQueueDepth == 0 && IsListEmpty(&Pcr->PrcbData.DpcData[0].DpcListHead)) ||
242 (Pcr->PrcbData.DpcData[0].DpcQueueDepth > 0 && !IsListEmpty(&Pcr->PrcbData.DpcData[0].DpcListHead)));
243 InsertHeadList(&Pcr->PrcbData.DpcData[0].DpcListHead,&Dpc->DpcListEntry);
244 DPRINT("Dpc->DpcListEntry.Flink %x\n", Dpc->DpcListEntry.Flink);
245 Pcr->PrcbData.DpcData[0].DpcQueueDepth++;
246 Dpc->Lock=(PULONG)1;
247 if (Pcr->PrcbData.MaximumDpcQueueDepth < Pcr->PrcbData.DpcData[0].DpcQueueDepth)
248 {
249 Pcr->PrcbData.MaximumDpcQueueDepth = Pcr->PrcbData.DpcData[0].DpcQueueDepth;
250 }
251 KiReleaseSpinLock(&Pcr->PrcbData.DpcData[0].DpcLock);
252 KeLowerIrql(oldlvl);
253 DPRINT("DpcQueueHead.Flink %x\n", Pcr->PrcbData.DpcData[0].DpcListHead.Flink);
254 DPRINT("Leaving KeInsertQueueDpc()\n",0);
255 return(TRUE);
256 }
257
258 /*
259 * FUNCTION: Specifies the DPCs importance
260 * ARGUMENTS:
261 * Dpc = Initalizes DPC
262 * Importance = DPC importance
263 * RETURNS: None
264 *
265 * @implemented
266 */
267 VOID STDCALL
268 KeSetImportanceDpc (IN PKDPC Dpc,
269 IN KDPC_IMPORTANCE Importance)
270 {
271 Dpc->Importance = Importance;
272 }
273
274 /*
275 * FUNCTION: Specifies on which processor the DPC will run
276 * ARGUMENTS:
277 * Dpc = Initalizes DPC
278 * Number = Processor number
279 * RETURNS: None
280 *
281 * @unimplemented
282 */
283 VOID STDCALL
284 KeSetTargetProcessorDpc (IN PKDPC Dpc,
285 IN CCHAR Number)
286 {
287 UNIMPLEMENTED;
288 }
289
290 VOID INIT_FUNCTION
291 KeInitDpc(VOID)
292 /*
293 * FUNCTION: Initialize DPC handling
294 */
295 {
296 PKPCR Pcr;
297 Pcr = KeGetCurrentKPCR();
298 InitializeListHead(&Pcr->PrcbData.DpcData[0].DpcListHead);
299 KeInitializeSpinLock(&Pcr->PrcbData.DpcData[0].DpcLock);
300 Pcr->PrcbData.MaximumDpcQueueDepth = 0;
301 Pcr->PrcbData.DpcData[0].DpcQueueDepth = 0;
302 }
303
304 /* EOF */