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>
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.
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.
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.
21 /* $Id: dpc.c,v 1.41 2004/10/30 23:48:56 navaraf Exp $
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)
30 * 12/3/99: Phillip Susi: Fixed IRQL problem
34 * NOTE: See also the higher level support routines in ntoskrnl/io/dpc.c
37 /* INCLUDES ***************************************************************/
41 #include <internal/debug.h>
43 /* TYPES *******************************************************************/
45 /* GLOBALS ******************************************************************/
47 /* FUNCTIONS ****************************************************************/
53 KeInitializeDpc (PKDPC Dpc
,
54 PKDEFERRED_ROUTINE DeferredRoutine
,
55 PVOID DeferredContext
)
57 * FUNCTION: Initalizes a DPC
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
66 Dpc
->DeferredRoutine
= DeferredRoutine
;
67 Dpc
->DeferredContext
= DeferredContext
;
75 KiDispatchInterrupt(VOID
)
77 * FUNCTION: Called to execute queued dpcs
80 PLIST_ENTRY current_entry
;
84 PKTHREAD CurrentThread
;
85 PKPROCESS CurrentProcess
;
87 ASSERT_IRQL(DISPATCH_LEVEL
);
89 Pcr
= KeGetCurrentKPCR();
91 if (Pcr
->PrcbData
.QuantumEnd
)
94 * FIXME: Various special cases should be handled here. The scripts
95 * from David B. Probert that describe it under KiQuantumEnd.
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
);
105 if (Pcr
->PrcbData
.DpcData
[0].DpcQueueDepth
== 0)
110 KeRaiseIrql(HIGH_LEVEL
, &oldlvl
);
111 KiAcquireSpinLock(&Pcr
->PrcbData
.DpcData
[0].DpcLock
);
113 while (!IsListEmpty(&Pcr
->PrcbData
.DpcData
[0].DpcListHead
))
115 ASSERT(Pcr
->PrcbData
.DpcData
[0].DpcQueueDepth
> 0);
117 current_entry
= RemoveHeadList(&Pcr
->PrcbData
.DpcData
[0].DpcListHead
);
118 Pcr
->PrcbData
.DpcData
[0].DpcQueueDepth
--;
119 Pcr
->PrcbData
.DpcData
[0].DpcCount
++;
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
)));
124 current
= CONTAINING_RECORD(current_entry
,KDPC
,DpcListEntry
);
126 Pcr
->PrcbData
.DpcRoutineActive
= 1;
127 KiReleaseSpinLock(&Pcr
->PrcbData
.DpcData
[0].DpcLock
);
129 current
->DeferredRoutine(current
,current
->DeferredContext
,
130 current
->SystemArgument1
,
131 current
->SystemArgument2
);
133 KeRaiseIrql(HIGH_LEVEL
, &oldlvl
);
134 KiAcquireSpinLock(&Pcr
->PrcbData
.DpcData
[0].DpcLock
);
135 Pcr
->PrcbData
.DpcRoutineActive
= 0;
138 KiReleaseSpinLock(&Pcr
->PrcbData
.DpcData
[0].DpcLock
);
163 return KeGetCurrentKPCR()->PrcbData
.DpcRoutineActive
;
170 KeRemoveQueueDpc (PKDPC Dpc
)
172 * FUNCTION: Removes DPC object from the system dpc queue
174 * Dpc = DPC to remove
175 * RETURNS: TRUE if the DPC was in the queue
183 Pcr
= KeGetCurrentKPCR();
185 KeRaiseIrql(HIGH_LEVEL
, &oldIrql
);
186 KiAcquireSpinLock(&Pcr
->PrcbData
.DpcData
[0].DpcLock
);
187 WasInQueue
= Dpc
->Lock
? TRUE
: FALSE
;
190 RemoveEntryList(&Dpc
->DpcListEntry
);
191 Pcr
->PrcbData
.DpcData
[0].DpcQueueDepth
--;
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
)));
198 KiReleaseSpinLock(&Pcr
->PrcbData
.DpcData
[0].DpcLock
);
199 KeLowerIrql(oldIrql
);
208 KeInsertQueueDpc (PKDPC Dpc
,
209 PVOID SystemArgument1
,
210 PVOID SystemArgument2
)
212 * FUNCTION: Queues a DPC for execution when the IRQL of a processor
213 * drops below DISPATCH_LEVEL
215 * Dpc = Initalizes DPC
216 * SystemArguments[1-2] = Undocumented
217 * RETURNS: TRUE if the DPC object wasn't already in the queue
224 DPRINT("KeInsertQueueDpc(dpc %x, SystemArgument1 %x, SystemArgument2 %x)\n",
225 Dpc
, SystemArgument1
, SystemArgument2
);
227 ASSERT(KeGetCurrentIrql()>=DISPATCH_LEVEL
);
230 Dpc
->Importance
=MediumImportance
;
231 Dpc
->SystemArgument1
=SystemArgument1
;
232 Dpc
->SystemArgument2
=SystemArgument2
;
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
++;
247 if (Pcr
->PrcbData
.MaximumDpcQueueDepth
< Pcr
->PrcbData
.DpcData
[0].DpcQueueDepth
)
249 Pcr
->PrcbData
.MaximumDpcQueueDepth
= Pcr
->PrcbData
.DpcData
[0].DpcQueueDepth
;
251 KiReleaseSpinLock(&Pcr
->PrcbData
.DpcData
[0].DpcLock
);
253 DPRINT("DpcQueueHead.Flink %x\n", Pcr
->PrcbData
.DpcData
[0].DpcListHead
.Flink
);
254 DPRINT("Leaving KeInsertQueueDpc()\n",0);
259 * FUNCTION: Specifies the DPCs importance
261 * Dpc = Initalizes DPC
262 * Importance = DPC importance
268 KeSetImportanceDpc (IN PKDPC Dpc
,
269 IN KDPC_IMPORTANCE Importance
)
271 Dpc
->Importance
= Importance
;
275 * FUNCTION: Specifies on which processor the DPC will run
277 * Dpc = Initalizes DPC
278 * Number = Processor number
284 KeSetTargetProcessorDpc (IN PKDPC Dpc
,
293 * FUNCTION: Initialize DPC handling
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;