9b6c2cb54fc5a1d3382ee7c2cd82f4c5f10dbbca
[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.38 2004/10/17 15:39:29 hbirr 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
85 assert_irql(DISPATCH_LEVEL);
86
87 Pcr = KeGetCurrentKPCR();
88
89 if (Pcr->PrcbData.DpcData[0].DpcQueueDepth == 0)
90 {
91 return;
92 }
93
94 KeRaiseIrql(HIGH_LEVEL, &oldlvl);
95 KiAcquireSpinLock(&Pcr->PrcbData.DpcData[0].DpcLock);
96
97 while (!IsListEmpty(&Pcr->PrcbData.DpcData[0].DpcListHead))
98 {
99 assert(Pcr->PrcbData.DpcData[0].DpcQueueDepth > 0);
100
101 current_entry = RemoveHeadList(&Pcr->PrcbData.DpcData[0].DpcListHead);
102 Pcr->PrcbData.DpcData[0].DpcQueueDepth--;
103 Pcr->PrcbData.DpcData[0].DpcCount++;
104
105 assert((Pcr->PrcbData.DpcData[0].DpcQueueDepth == 0 && IsListEmpty(&Pcr->PrcbData.DpcData[0].DpcListHead)) ||
106 (Pcr->PrcbData.DpcData[0].DpcQueueDepth > 0 && !IsListEmpty(&Pcr->PrcbData.DpcData[0].DpcListHead)));
107
108 current = CONTAINING_RECORD(current_entry,KDPC,DpcListEntry);
109 current->Lock=FALSE;
110 Pcr->PrcbData.DpcRoutineActive = 1;
111 KiReleaseSpinLock(&Pcr->PrcbData.DpcData[0].DpcLock);
112 KeLowerIrql(oldlvl);
113 current->DeferredRoutine(current,current->DeferredContext,
114 current->SystemArgument1,
115 current->SystemArgument2);
116
117 KeRaiseIrql(HIGH_LEVEL, &oldlvl);
118 KiAcquireSpinLock(&Pcr->PrcbData.DpcData[0].DpcLock);
119 Pcr->PrcbData.DpcRoutineActive = 0;
120 }
121
122 KiReleaseSpinLock(&Pcr->PrcbData.DpcData[0].DpcLock);
123 KeLowerIrql(oldlvl);
124 }
125
126 /*
127 * @unimplemented
128 */
129 VOID
130 STDCALL
131 KeFlushQueuedDpcs(
132 VOID
133 )
134 {
135 UNIMPLEMENTED;
136 }
137
138 /*
139 * @implemented
140 */
141 BOOLEAN
142 STDCALL
143 KeIsExecutingDpc(
144 VOID
145 )
146 {
147 return KeGetCurrentKPCR()->PrcbData.DpcRoutineActive;
148 }
149
150 /*
151 * @implemented
152 */
153 BOOLEAN STDCALL
154 KeRemoveQueueDpc (PKDPC Dpc)
155 /*
156 * FUNCTION: Removes DPC object from the system dpc queue
157 * ARGUMENTS:
158 * Dpc = DPC to remove
159 * RETURNS: TRUE if the DPC was in the queue
160 * FALSE otherwise
161 */
162 {
163 KIRQL oldIrql;
164 BOOLEAN WasInQueue;
165 PKPCR Pcr;
166
167 Pcr = KeGetCurrentKPCR();
168
169 KeRaiseIrql(HIGH_LEVEL, &oldIrql);
170 KiAcquireSpinLock(&Pcr->PrcbData.DpcData[0].DpcLock);
171 WasInQueue = Dpc->Lock ? TRUE : FALSE;
172 if (WasInQueue)
173 {
174 RemoveEntryList(&Dpc->DpcListEntry);
175 Pcr->PrcbData.DpcData[0].DpcQueueDepth--;
176 Dpc->Lock=0;
177 }
178
179 assert((Pcr->PrcbData.DpcData[0].DpcQueueDepth == 0 && IsListEmpty(&Pcr->PrcbData.DpcData[0].DpcListHead)) ||
180 (Pcr->PrcbData.DpcData[0].DpcQueueDepth > 0 && !IsListEmpty(&Pcr->PrcbData.DpcData[0].DpcListHead)));
181
182 KiReleaseSpinLock(&Pcr->PrcbData.DpcData[0].DpcLock);
183 KeLowerIrql(oldIrql);
184
185 return WasInQueue;
186 }
187
188 /*
189 * @implemented
190 */
191 BOOLEAN STDCALL
192 KeInsertQueueDpc (PKDPC Dpc,
193 PVOID SystemArgument1,
194 PVOID SystemArgument2)
195 /*
196 * FUNCTION: Queues a DPC for execution when the IRQL of a processor
197 * drops below DISPATCH_LEVEL
198 * ARGUMENTS:
199 * Dpc = Initalizes DPC
200 * SystemArguments[1-2] = Undocumented
201 * RETURNS: TRUE if the DPC object wasn't already in the queue
202 * FALSE otherwise
203 */
204 {
205 KIRQL oldlvl;
206 PKPCR Pcr;
207
208 DPRINT("KeInsertQueueDpc(dpc %x, SystemArgument1 %x, SystemArgument2 %x)\n",
209 Dpc, SystemArgument1, SystemArgument2);
210
211 assert(KeGetCurrentIrql()>=DISPATCH_LEVEL);
212
213 Dpc->Number=0;
214 Dpc->Importance=MediumImportance;
215 Dpc->SystemArgument1=SystemArgument1;
216 Dpc->SystemArgument2=SystemArgument2;
217 if (Dpc->Lock)
218 {
219 return(FALSE);
220 }
221
222 Pcr = KeGetCurrentKPCR();
223 KeRaiseIrql(HIGH_LEVEL, &oldlvl);
224 KiAcquireSpinLock(&Pcr->PrcbData.DpcData[0].DpcLock);
225 assert((Pcr->PrcbData.DpcData[0].DpcQueueDepth == 0 && IsListEmpty(&Pcr->PrcbData.DpcData[0].DpcListHead)) ||
226 (Pcr->PrcbData.DpcData[0].DpcQueueDepth > 0 && !IsListEmpty(&Pcr->PrcbData.DpcData[0].DpcListHead)));
227 InsertHeadList(&Pcr->PrcbData.DpcData[0].DpcListHead,&Dpc->DpcListEntry);
228 DPRINT("Dpc->DpcListEntry.Flink %x\n", Dpc->DpcListEntry.Flink);
229 Pcr->PrcbData.DpcData[0].DpcQueueDepth++;
230 Dpc->Lock=(PULONG)1;
231 if (Pcr->PrcbData.MaximumDpcQueueDepth < Pcr->PrcbData.DpcData[0].DpcQueueDepth)
232 {
233 Pcr->PrcbData.MaximumDpcQueueDepth = Pcr->PrcbData.DpcData[0].DpcQueueDepth;
234 }
235 KiReleaseSpinLock(&Pcr->PrcbData.DpcData[0].DpcLock);
236 KeLowerIrql(oldlvl);
237 DPRINT("DpcQueueHead.Flink %x\n",DpcQueueHead.Flink);
238 DPRINT("Leaving KeInsertQueueDpc()\n",0);
239 return(TRUE);
240 }
241
242 /*
243 * FUNCTION: Specifies the DPCs importance
244 * ARGUMENTS:
245 * Dpc = Initalizes DPC
246 * Importance = DPC importance
247 * RETURNS: None
248 *
249 * @implemented
250 */
251 VOID STDCALL
252 KeSetImportanceDpc (IN PKDPC Dpc,
253 IN KDPC_IMPORTANCE Importance)
254 {
255 Dpc->Importance = Importance;
256 }
257
258 /*
259 * FUNCTION: Specifies on which processor the DPC will run
260 * ARGUMENTS:
261 * Dpc = Initalizes DPC
262 * Number = Processor number
263 * RETURNS: None
264 *
265 * @unimplemented
266 */
267 VOID STDCALL
268 KeSetTargetProcessorDpc (IN PKDPC Dpc,
269 IN CCHAR Number)
270 {
271 UNIMPLEMENTED;
272 }
273
274 VOID INIT_FUNCTION
275 KeInitDpc(VOID)
276 /*
277 * FUNCTION: Initialize DPC handling
278 */
279 {
280 PKPCR Pcr;
281 Pcr = KeGetCurrentKPCR();
282 InitializeListHead(&Pcr->PrcbData.DpcData[0].DpcListHead);
283 KeInitializeSpinLock(&Pcr->PrcbData.DpcData[0].DpcLock);
284 Pcr->PrcbData.MaximumDpcQueueDepth = 0;
285 Pcr->PrcbData.DpcData[0].DpcQueueDepth = 0;
286 }
287
288 /* EOF */