2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ke/gate.c
5 * PURPOSE: Implements the Gate Dispatcher Object
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES *****************************************************************/
13 #include <internal/debug.h>
15 /* FUNCTIONS ****************************************************************/
19 KeInitializeGate(IN PKGATE Gate
)
21 /* Initialize the Dispatcher Header */
22 KeInitializeDispatcherHeader(&Gate
->Header
,
24 sizeof(Gate
) / sizeof(ULONG
),
30 KeWaitForGate(IN PKGATE Gate
,
31 IN KWAIT_REASON WaitReason
,
32 IN KPROCESSOR_MODE WaitMode
)
34 KLOCK_QUEUE_HANDLE ApcLock
;
35 PKTHREAD Thread
= KeGetCurrentThread();
36 PKWAIT_BLOCK GateWaitBlock
;
40 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
45 /* Acquire the APC lock */
46 KiAcquireApcLock(Thread
, &ApcLock
);
48 /* Check if a kernel APC is pending and we're below APC_LEVEL */
49 if ((Thread
->ApcState
.KernelApcPending
) &&
50 !(Thread
->SpecialApcDisable
) &&
51 (ApcLock
.OldIrql
< APC_LEVEL
))
53 /* Release the lock, this will fire the APC */
54 KiReleaseApcLock(&ApcLock
);
58 /* Check if we have a queue and lock the dispatcher if so */
59 Queue
= Thread
->Queue
;
60 if (Queue
) KiAcquireDispatcherLockAtDpcLevel();
63 KiAcquireThreadLock(Thread
);
66 KiAcquireDispatcherObject(&Gate
->Header
);
68 /* Check if it's already signaled */
69 if (Gate
->Header
.SignalState
)
72 Gate
->Header
.SignalState
= 0;
74 /* Release the gate and thread locks */
75 KiReleaseDispatcherObject(&Gate
->Header
);
76 KiReleaseThreadLock(Thread
);
78 /* Release the APC lock and return */
79 KiReleaseApcLock(&ApcLock
);
83 /* Setup a Wait Block */
84 GateWaitBlock
= &Thread
->WaitBlock
[0];
85 GateWaitBlock
->Object
= (PVOID
)Gate
;
86 GateWaitBlock
->Thread
= Thread
;
88 /* Set the Thread Wait Data */
89 Thread
->WaitMode
= WaitMode
;
90 Thread
->WaitReason
= WaitReason
;
91 Thread
->WaitIrql
= ApcLock
.OldIrql
;
92 Thread
->State
= GateWait
;
93 Thread
->GateObject
= Gate
;
95 /* Insert into the Wait List */
96 InsertTailList(&Gate
->Header
.WaitListHead
,
97 &GateWaitBlock
->WaitListEntry
);
99 /* Release the gate lock */
100 KiReleaseDispatcherObject(&Gate
->Header
);
103 KiSetThreadSwapBusy(Thread
);
105 /* Release the thread lock */
106 KiReleaseThreadLock(Thread
);
108 /* Check if we had a queue */
112 KiActivateWaiterQueue(Queue
);
114 /* Release the dispatcher lock */
115 KiReleaseDispatcherLockFromDpcLevel();
118 /* Release the APC lock but stay at DPC level */
119 KiReleaseApcLockFromDpcLevel(&ApcLock
);
121 /* Find a new thread to run */
122 Status
= KiSwapThread(Thread
, KeGetCurrentPrcb());
124 /* Make sure we weren't executing an APC */
125 if (Status
== STATUS_SUCCESS
) return;
132 KeSignalGateBoostPriority(IN PKGATE Gate
)
135 PKWAIT_BLOCK WaitBlock
;
138 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
140 /* Start entry loop */
143 /* Raise to synch level */
144 OldIrql
= KeRaiseIrqlToSynchLevel();
147 KiAcquireDispatcherObject(&Gate
->Header
);
149 /* Make sure we're not already signaled or that the list is empty */
150 if (Gate
->Header
.SignalState
) break;
152 /* Check if our wait list is empty */
153 if (IsListEmpty(&Gate
->Header
.WaitListHead
))
155 /* It is, so signal the event */
156 Gate
->Header
.SignalState
= 1;
162 WaitBlock
= CONTAINING_RECORD(Gate
->Header
.WaitListHead
.Flink
,
166 /* Get the Associated thread */
167 WaitThread
= WaitBlock
->Thread
;
169 /* Check to see if the waiting thread is locked */
170 if (!KiTryThreadLock(WaitThread
))
172 /* Unlock the gate */
173 KiReleaseDispatcherObject(&Gate
->Header
);
175 /* Lower IRQL and loop again */
176 KeLowerIrql(OldIrql
);
181 RemoveEntryList(&WaitBlock
->WaitListEntry
);
183 /* Clear wait status */
184 WaitThread
->WaitStatus
= STATUS_SUCCESS
;
186 /* Set state and CPU */
187 WaitThread
->State
= DeferredReady
;
188 WaitThread
->DeferredProcessor
= KeGetCurrentPrcb()->Number
;
190 /* Release the gate lock */
191 KiReleaseDispatcherObject(&Gate
->Header
);
193 /* Release the thread lock */
194 KiReleaseThreadLock(WaitThread
);
196 /* FIXME: Boosting */
198 /* Check if we have a queue */
199 if (WaitThread
->Queue
)
201 /* Acquire the dispatcher lock */
202 KiAcquireDispatcherLockAtDpcLevel();
204 /* Check if we still have one */
205 if (WaitThread
->Queue
)
207 /* Increment active threads */
208 WaitThread
->Queue
->CurrentCount
++;
212 KiReleaseDispatcherLockFromDpcLevel();
215 /* Make the thread ready */
216 KiReadyThread(WaitThread
);
218 /* Exit the dispatcher */
219 KiExitDispatcher(OldIrql
);
224 /* If we got here, then there's no rescheduling. */
225 KiReleaseDispatcherObject(&Gate
->Header
);
226 KeLowerIrql(OldIrql
);