update for HEAD-2003091401
[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 static LIST_ENTRY DpcQueueHead; /* Head of the list of pending DPCs */
50 static KSPIN_LOCK DpcQueueLock; /* Lock for the above list */
51 /* 
52  * Number of pending DPCs. This is inspected by
53  * the idle thread to determine if the queue needs to
54  * be run down
55  */
56 ULONG DpcQueueSize = 0; 
57
58 /* FUNCTIONS ****************************************************************/
59
60 /*
61  * @implemented
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 /*
83  * @implemented
84  */
85 VOID STDCALL 
86 KiDispatchInterrupt(VOID)
87 /*
88  * FUNCTION: Called to execute queued dpcs
89  */
90 {
91    PLIST_ENTRY current_entry;
92    PKDPC current;
93    KIRQL oldlvl;
94    
95    assert_irql(DISPATCH_LEVEL);
96    
97    if (DpcQueueSize == 0)
98      {
99         return;
100      }
101    
102    KeRaiseIrql(HIGH_LEVEL, &oldlvl);
103    KeAcquireSpinLockAtDpcLevel(&DpcQueueLock);
104
105    while (!IsListEmpty(&DpcQueueHead))
106    {
107       current_entry = RemoveHeadList(&DpcQueueHead);
108       DpcQueueSize--;
109       current = CONTAINING_RECORD(current_entry,KDPC,DpcListEntry);
110       current->Lock=FALSE;
111       KeReleaseSpinLock(&DpcQueueLock, oldlvl);
112       current->DeferredRoutine(current,current->DeferredContext,
113                                current->SystemArgument1,
114                                current->SystemArgument2);
115
116       KeRaiseIrql(HIGH_LEVEL, &oldlvl);
117       KeAcquireSpinLockAtDpcLevel(&DpcQueueLock);
118    }
119    KeReleaseSpinLock(&DpcQueueLock, oldlvl);
120 }
121
122 /*
123  * @implemented
124  */
125 BOOLEAN STDCALL 
126 KeRemoveQueueDpc (PKDPC Dpc)
127 /*
128  * FUNCTION: Removes DPC object from the system dpc queue
129  * ARGUMENTS:
130  *          Dpc = DPC to remove
131  * RETURNS: TRUE if the DPC was in the queue
132  *          FALSE otherwise
133  */
134 {
135    KIRQL oldIrql;
136    
137    KeRaiseIrql(HIGH_LEVEL, &oldIrql);
138    KeAcquireSpinLockAtDpcLevel(&DpcQueueLock);
139    if (!Dpc->Lock)
140      {
141         KeReleaseSpinLock(&DpcQueueLock, oldIrql);
142         return(FALSE);
143      }
144    RemoveEntryList(&Dpc->DpcListEntry);
145    DpcQueueSize--;
146    Dpc->Lock=0;
147    KeReleaseSpinLock(&DpcQueueLock, oldIrql);
148    return(TRUE);
149 }
150
151 /*
152  * @implemented
153  */
154 BOOLEAN STDCALL 
155 KeInsertQueueDpc (PKDPC Dpc,
156                   PVOID SystemArgument1,
157                   PVOID SystemArgument2)
158 /*
159  * FUNCTION: Queues a DPC for execution when the IRQL of a processor
160  * drops below DISPATCH_LEVEL
161  * ARGUMENTS:
162  *          Dpc = Initalizes DPC
163  *          SystemArguments[1-2] = Undocumented
164  * RETURNS: TRUE if the DPC object wasn't already in the queue
165  *          FALSE otherwise
166  */
167 {
168    KIRQL oldlvl;
169    DPRINT("KeInsertQueueDpc(dpc %x, SystemArgument1 %x, SystemArgument2 %x)\n",
170           Dpc, SystemArgument1, SystemArgument2);
171
172    assert(KeGetCurrentIrql()>=DISPATCH_LEVEL);
173
174    Dpc->Number=0;
175    Dpc->Importance=MediumImportance;
176    Dpc->SystemArgument1=SystemArgument1;
177    Dpc->SystemArgument2=SystemArgument2;
178    if (Dpc->Lock)
179      {
180         return(FALSE);
181      }
182    KeRaiseIrql(HIGH_LEVEL, &oldlvl);
183    KeAcquireSpinLockAtDpcLevel(&DpcQueueLock);
184    InsertHeadList(&DpcQueueHead,&Dpc->DpcListEntry);
185    DPRINT("Dpc->DpcListEntry.Flink %x\n", Dpc->DpcListEntry.Flink);
186    DpcQueueSize++;
187    Dpc->Lock=(PULONG)1;
188    KeReleaseSpinLock( &DpcQueueLock, oldlvl );
189    DPRINT("DpcQueueHead.Flink %x\n",DpcQueueHead.Flink);
190    DPRINT("Leaving KeInsertQueueDpc()\n",0);
191    return(TRUE);
192 }
193
194 /*
195  * FUNCTION: Specifies the DPCs importance
196  * ARGUMENTS:
197  *          Dpc = Initalizes DPC
198  *          Importance = DPC importance
199  * RETURNS: None
200  *
201  * @implemented
202  */
203 VOID STDCALL
204 KeSetImportanceDpc (IN  PKDPC           Dpc,
205                     IN  KDPC_IMPORTANCE Importance)
206 {
207         Dpc->Importance = Importance;
208 }
209
210 /*
211  * FUNCTION: Specifies on which processor the DPC will run
212  * ARGUMENTS:
213  *          Dpc = Initalizes DPC
214  *          Number = Processor number
215  * RETURNS: None
216  *
217  * @unimplemented
218  */
219 VOID STDCALL
220 KeSetTargetProcessorDpc (IN     PKDPC   Dpc,
221                          IN     CCHAR   Number)
222 {
223         UNIMPLEMENTED;
224 }
225
226 VOID 
227 KeInitDpc(VOID)
228 /*
229  * FUNCTION: Initialize DPC handling
230  */
231 {
232    InitializeListHead(&DpcQueueHead);
233    KeInitializeSpinLock(&DpcQueueLock);
234 }
235
236 /* EOF */