fixed sync bug by elevating IRQL
[reactos.git] / reactos / ntoskrnl / ke / dpc.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ke/dpc.c
5 * PURPOSE: Handle DPCs (Delayed Procedure Calls)
6 * PROGRAMMER: David Welch (welch@mcmail.com)
7 * UPDATE HISTORY:
8 * 28/05/98: Created
9 * 12/3/99: Phillip Susi: Fixed IRQL problem
10 */
11
12 /*
13 * NOTE: See also the higher level support routines in ntoskrnl/io/dpc.c
14 */
15
16 /* INCLUDES ***************************************************************/
17
18 #include <ddk/ntddk.h>
19
20 #define NDEBUG
21 #include <internal/debug.h>
22
23 /* TYPES *******************************************************************/
24
25 /* GLOBALS ******************************************************************/
26
27 static LIST_ENTRY DpcQueueHead;
28 static KSPIN_LOCK DpcQueueLock;
29 ULONG DpcQueueSize = 0;
30
31 /* FUNCTIONS ****************************************************************/
32
33 VOID KeInitializeDpc(PKDPC Dpc, PKDEFERRED_ROUTINE DeferredRoutine,
34 PVOID DeferredContext)
35 /*
36 * FUNCTION: Initalizes a DPC
37 * ARGUMENTS:
38 * Dpc = Caller supplied DPC to be initialized
39 * DeferredRoutine = Associated DPC callback
40 * DeferredContext = Parameter to be passed to the callback
41 * NOTE: Callers must be running at IRQL PASSIVE_LEVEL
42 */
43 {
44 Dpc->Type=0;
45 Dpc->DeferredRoutine=DeferredRoutine;
46 Dpc->DeferredContext=DeferredContext;
47 Dpc->Lock=0;
48 }
49
50 void KeDrainDpcQueue(void)
51 /*
52 * FUNCTION: Called to execute queued dpcs
53 */
54 {
55 PLIST_ENTRY current_entry;
56 PKDPC current;
57 KIRQL oldlvl;
58
59 assert_irql(DISPATCH_LEVEL);
60
61 if (DpcQueueSize == 0)
62 {
63 return;
64 }
65 DPRINT("KeDrainDpcQueue()\n");
66
67 KeAcquireSpinLockAtDpcLevel(&DpcQueueLock);
68 KeRaiseIrql(HIGH_LEVEL,&oldlvl);
69 current_entry = RemoveHeadList(&DpcQueueHead);
70 KeLowerIrql(oldlvl);
71 current = CONTAINING_RECORD(current_entry,KDPC,DpcListEntry);
72 while (current_entry!=(&DpcQueueHead))
73 {
74 CHECKPOINT;
75 DPRINT("DpcQueueSize %d current %x current->DeferredContext %x\n",
76 DpcQueueSize, current, current->DeferredContext);
77 DPRINT("current->Flink %x\n", current->DpcListEntry.Flink);
78 current->DeferredRoutine(current,current->DeferredContext,
79 current->SystemArgument1,
80 current->SystemArgument2);
81 CHECKPOINT;
82 current->Lock=FALSE;
83 KeRaiseIrql(HIGH_LEVEL,&oldlvl);
84 current_entry = RemoveHeadList(&DpcQueueHead);
85 DPRINT("current_entry %x\n", current_entry);
86 DpcQueueSize--;
87 KeLowerIrql(oldlvl);
88 current = CONTAINING_RECORD(current_entry,KDPC,DpcListEntry);
89 DPRINT("current %x\n", current);
90 }
91 KeReleaseSpinLockFromDpcLevel(&DpcQueueLock);
92 }
93
94 BOOLEAN KeRemoveQueueDpc(PKDPC Dpc)
95 /*
96 * FUNCTION: Removes DPC object from the system dpc queue
97 * ARGUMENTS:
98 * Dpc = DPC to remove
99 * RETURNS: TRUE if the DPC was in the queue
100 * FALSE otherwise
101 */
102 {
103 KIRQL oldIrql;
104
105 KeAcquireSpinLockAtDpcLevel( &DpcQueueLock );
106 KeRaiseIrql( HIGH_LEVEL, &oldIrql );
107 if (!Dpc->Lock)
108 {
109 KeReleaseSpinLock(&DpcQueueLock, oldIrql);
110 return(FALSE);
111 }
112 RemoveEntryList(&Dpc->DpcListEntry);
113 DpcQueueSize--;
114 Dpc->Lock=0;
115 KeReleaseSpinLock(&DpcQueueLock, oldIrql);
116 return(TRUE);
117 }
118
119 BOOLEAN KeInsertQueueDpc(PKDPC dpc, PVOID SystemArgument1,
120 PVOID SystemArgument2)
121 /*
122 * FUNCTION: Queues a DPC for execution when the IRQL of a processor
123 * drops below DISPATCH_LEVEL
124 * ARGUMENTS:
125 * Dpc = Initalizes DPC
126 * SystemArguments[1-2] = Undocumented
127 * RETURNS: TRUE if the DPC object wasn't already in the queue
128 * FALSE otherwise
129 */
130 {
131 KIRQL oldlvl;
132 DPRINT("KeInsertQueueDpc(dpc %x, SystemArgument1 %x, SystemArgument2 %x)\n",
133 dpc, SystemArgument1, SystemArgument2);
134
135 assert(KeGetCurrentIrql()>=DISPATCH_LEVEL);
136
137 dpc->Number=0;
138 dpc->Importance=Medium;
139 dpc->SystemArgument1=SystemArgument1;
140 dpc->SystemArgument2=SystemArgument2;
141 if (dpc->Lock)
142 {
143 return(FALSE);
144 }
145 KeRaiseIrql( HIGH_LEVEL, &oldlvl );
146 KeAcquireSpinLockAtDpcLevel(&DpcQueueLock);
147 InsertHeadList(&DpcQueueHead,&dpc->DpcListEntry);
148 DPRINT("dpc->DpcListEntry.Flink %x\n", dpc->DpcListEntry.Flink);
149 DpcQueueSize++;
150 KeReleaseSpinLock( &DpcQueueLock, oldlvl );
151 dpc->Lock=(PULONG)1;
152 DPRINT("DpcQueueHead.Flink %x\n",DpcQueueHead.Flink);
153 DPRINT("Leaving KeInsertQueueDpc()\n",0);
154 return(TRUE);
155 }
156
157 void KeInitDpc(void)
158 /*
159 * FUNCTION: Initialize DPC handling
160 */
161 {
162 InitializeListHead(&DpcQueueHead);
163 KeInitializeSpinLock(&DpcQueueLock);
164 }
165