Don't remove the WaitEntry twice (in KiInsertQueue).
[reactos.git] / reactos / ntoskrnl / ke / gate.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel
4 * FILE: ntoskrnl/ke/gate.c
5 * PURPOSE: Implements the Gate Dispatcher Object
6 *
7 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <internal/debug.h>
15
16 /* FUNCTIONS ****************************************************************/
17
18 VOID
19 FASTCALL
20 KeInitializeGate(PKGATE Gate)
21 {
22 DPRINT("KeInitializeGate(Gate %x)\n", Gate);
23
24 /* Initialize the Dispatcher Header */
25 KeInitializeDispatcherHeader(&Gate->Header,
26 GateObject,
27 sizeof(Gate) / sizeof(ULONG),
28 0);
29 }
30
31 VOID
32 FASTCALL
33 KeWaitForGate(PKGATE Gate,
34 KWAIT_REASON WaitReason,
35 KPROCESSOR_MODE WaitMode)
36 {
37 KIRQL OldIrql;
38 PKTHREAD CurrentThread = KeGetCurrentThread();
39 PKWAIT_BLOCK GateWaitBlock;
40 NTSTATUS Status;
41
42 DPRINT("KeWaitForGate(Gate %x)\n", Gate);
43
44 do
45 {
46 /* Lock the APC Queue */
47 OldIrql = KeAcquireDispatcherDatabaseLock();
48
49 /* Check if it's already signaled */
50 if (Gate->Header.SignalState)
51 {
52 /* Unsignal it */
53 Gate->Header.SignalState = 0;
54
55 /* Unlock the Queue and return */
56 KeReleaseDispatcherDatabaseLock(OldIrql);
57 return;
58 }
59
60 /* Setup a Wait Block */
61 GateWaitBlock = &CurrentThread->WaitBlock[0];
62 GateWaitBlock->Object = (PVOID)Gate;
63 GateWaitBlock->Thread = CurrentThread;
64
65 /* Set the Thread Wait Data */
66 CurrentThread->WaitIrql = OldIrql;
67 CurrentThread->GateObject = Gate;
68
69 /* Insert into the Wait List */
70 InsertTailList(&Gate->Header.WaitListHead,
71 &GateWaitBlock->WaitListEntry);
72
73 /* Handle Kernel Queues */
74 if (CurrentThread->Queue)
75 {
76 DPRINT("Waking Queue\n");
77 KiWakeQueue(CurrentThread->Queue);
78 }
79
80 /* Setup the wait information */
81 CurrentThread->WaitMode = WaitMode;
82 CurrentThread->WaitReason = WaitReason;
83 CurrentThread->WaitTime = ((PLARGE_INTEGER)&KeTickCount)->LowPart;
84 CurrentThread->State = Waiting;
85
86 /* Find a new thread to run */
87 DPRINT("Swapping threads\n");
88 Status = KiSwapThread();
89
90 /* Check if we were executing an APC */
91 if (Status != STATUS_KERNEL_APC) return;
92
93 DPRINT("Looping Again\n");
94 } while (TRUE);
95 }
96
97 VOID
98 FASTCALL
99 KeSignalGateBoostPriority(PKGATE Gate)
100 {
101 PKTHREAD WaitThread;
102 PKWAIT_BLOCK WaitBlock;
103 KIRQL OldIrql;
104 NTSTATUS WaitStatus = STATUS_SUCCESS;
105
106 DPRINT("KeSignalGateBoostPriority(EveGate %x)\n", Gate);
107
108 /* Acquire Dispatcher Database Lock */
109 OldIrql = KeAcquireDispatcherDatabaseLock();
110
111 /* Make sure we're not already signaled or that the list is empty */
112 if (Gate->Header.SignalState) goto quit;
113
114 /* If our wait list is empty, then signal the event and return */
115 if (IsListEmpty(&Gate->Header.WaitListHead))
116 {
117 Gate->Header.SignalState = 1;
118 goto quit;
119 }
120
121 /* Get WaitBlock */
122 WaitBlock = CONTAINING_RECORD(Gate->Header.WaitListHead.Flink,
123 KWAIT_BLOCK,
124 WaitListEntry);
125 /* Remove it */
126 RemoveEntryList(&WaitBlock->WaitListEntry);
127
128 /* Get the Associated thread */
129 WaitThread = WaitBlock->Thread;
130
131 /* Increment the Queue's active threads */
132 if (WaitThread->Queue)
133 {
134 DPRINT("Incrementing Queue's active threads\n");
135 WaitThread->Queue->CurrentCount++;
136 }
137
138 /* Reschedule the Thread */
139 DPRINT("Unblocking the Thread\n");
140 KiUnblockThread(WaitThread, &WaitStatus, EVENT_INCREMENT);
141 return;
142
143 quit:
144 /* Release the Dispatcher Database Lock */
145 KeReleaseDispatcherDatabaseLock(OldIrql);
146 }
147
148 /* EOF */