:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[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 VOID STDCALL 
61 KeInitializeDpc (PKDPC                  Dpc,
62                  PKDEFERRED_ROUTINE     DeferredRoutine,
63                  PVOID                  DeferredContext)
64 /*
65  * FUNCTION: Initalizes a DPC
66  * ARGUMENTS:
67  *          Dpc = Caller supplied DPC to be initialized
68  *          DeferredRoutine = Associated DPC callback
69  *          DeferredContext = Parameter to be passed to the callback
70  * NOTE: Callers must be running at IRQL PASSIVE_LEVEL
71  */
72 {
73    Dpc->Type = 0;
74    Dpc->DeferredRoutine = DeferredRoutine;
75    Dpc->DeferredContext = DeferredContext;
76    Dpc->Lock = 0;
77 }
78
79 VOID STDCALL 
80 KiDispatchInterrupt(VOID)
81 /*
82  * FUNCTION: Called to execute queued dpcs
83  */
84 {
85    PLIST_ENTRY current_entry;
86    PKDPC current;
87    KIRQL oldlvl;
88    
89    assert_irql(DISPATCH_LEVEL);
90    
91    if (DpcQueueSize == 0)
92      {
93         return;
94      }
95    
96    KeRaiseIrql(HIGH_LEVEL, &oldlvl);
97    KeAcquireSpinLockAtDpcLevel(&DpcQueueLock);
98    current_entry = RemoveHeadList(&DpcQueueHead);
99    if (current_entry != &DpcQueueHead)
100      {
101        DpcQueueSize--;
102      }
103    KeReleaseSpinLockFromDpcLevel(&DpcQueueLock);
104    current = CONTAINING_RECORD(current_entry,KDPC,DpcListEntry);
105    current->Lock=FALSE;
106    KeLowerIrql(oldlvl);
107    while (current_entry!=(&DpcQueueHead))
108      {
109         current->DeferredRoutine(current,current->DeferredContext,
110                                  current->SystemArgument1,
111                                  current->SystemArgument2);
112
113         KeRaiseIrql(HIGH_LEVEL, &oldlvl);
114         KeAcquireSpinLockAtDpcLevel(&DpcQueueLock);
115         current_entry = RemoveHeadList(&DpcQueueHead);
116         if (current_entry != &DpcQueueHead)
117           {
118             DpcQueueSize--;
119           }
120         KeReleaseSpinLockFromDpcLevel(&DpcQueueLock);
121         current = CONTAINING_RECORD(current_entry,KDPC,DpcListEntry);
122         current->Lock=FALSE;
123         KeLowerIrql(oldlvl);
124      }
125 }
126
127 BOOLEAN STDCALL 
128 KeRemoveQueueDpc (PKDPC Dpc)
129 /*
130  * FUNCTION: Removes DPC object from the system dpc queue
131  * ARGUMENTS:
132  *          Dpc = DPC to remove
133  * RETURNS: TRUE if the DPC was in the queue
134  *          FALSE otherwise
135  */
136 {
137    KIRQL oldIrql;
138    
139    KeAcquireSpinLockAtDpcLevel(&DpcQueueLock);
140    KeRaiseIrql(HIGH_LEVEL, &oldIrql);
141    if (!Dpc->Lock)
142      {
143         KeReleaseSpinLock(&DpcQueueLock, oldIrql);
144         return(FALSE);
145      }
146    RemoveEntryList(&Dpc->DpcListEntry);
147    DpcQueueSize--;
148    Dpc->Lock=0;
149    KeReleaseSpinLock(&DpcQueueLock, oldIrql);
150    return(TRUE);
151 }
152
153 BOOLEAN STDCALL 
154 KeInsertQueueDpc (PKDPC Dpc,
155                   PVOID SystemArgument1,
156                   PVOID SystemArgument2)
157 /*
158  * FUNCTION: Queues a DPC for execution when the IRQL of a processor
159  * drops below DISPATCH_LEVEL
160  * ARGUMENTS:
161  *          Dpc = Initalizes DPC
162  *          SystemArguments[1-2] = Undocumented
163  * RETURNS: TRUE if the DPC object wasn't already in the queue
164  *          FALSE otherwise
165  */
166 {
167    KIRQL oldlvl;
168    DPRINT("KeInsertQueueDpc(dpc %x, SystemArgument1 %x, SystemArgument2 %x)\n",
169           Dpc, SystemArgument1, SystemArgument2);
170
171    assert(KeGetCurrentIrql()>=DISPATCH_LEVEL);
172
173    Dpc->Number=0;
174    Dpc->Importance=MediumImportance;
175    Dpc->SystemArgument1=SystemArgument1;
176    Dpc->SystemArgument2=SystemArgument2;
177    if (Dpc->Lock)
178      {
179         return(FALSE);
180      }
181    KeRaiseIrql(HIGH_LEVEL, &oldlvl);
182    KeAcquireSpinLockAtDpcLevel(&DpcQueueLock);
183    InsertHeadList(&DpcQueueHead,&Dpc->DpcListEntry);
184    DPRINT("Dpc->DpcListEntry.Flink %x\n", Dpc->DpcListEntry.Flink);
185    DpcQueueSize++;
186    Dpc->Lock=(PULONG)1;
187    KeReleaseSpinLock( &DpcQueueLock, oldlvl );
188    DPRINT("DpcQueueHead.Flink %x\n",DpcQueueHead.Flink);
189    DPRINT("Leaving KeInsertQueueDpc()\n",0);
190    return(TRUE);
191 }
192
193 /*
194  * FUNCTION: Specifies the DPCs importance
195  * ARGUMENTS:
196  *          Dpc = Initalizes DPC
197  *          Importance = DPC importance
198  * RETURNS: None
199  */
200 VOID STDCALL
201 KeSetImportanceDpc (IN  PKDPC           Dpc,
202                     IN  KDPC_IMPORTANCE Importance)
203 {
204         Dpc->Importance = Importance;
205 }
206
207 /*
208  * FUNCTION: Specifies on which processor the DPC will run
209  * ARGUMENTS:
210  *          Dpc = Initalizes DPC
211  *          Number = Processor number
212  * RETURNS: None
213  */
214 VOID STDCALL
215 KeSetTargetProcessorDpc (IN     PKDPC   Dpc,
216                          IN     CCHAR   Number)
217 {
218         UNIMPLEMENTED;
219 }
220
221 VOID 
222 KeInitDpc(VOID)
223 /*
224  * FUNCTION: Initialize DPC handling
225  */
226 {
227    InitializeListHead(&DpcQueueHead);
228    KeInitializeSpinLock(&DpcQueueLock);
229 }
230
231 /* EOF */