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