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 *****************************************************************/
15 /* FUNCTIONS ****************************************************************/
19 KeInitializeGate(IN PKGATE Gate
)
21 /* Initialize the Dispatcher Header */
22 KeInitializeDispatcherHeader(&Gate
->Header
,
24 sizeof(KGATE
) / 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 gate lock */
79 if (Queue
) KiReleaseDispatcherLockFromDpcLevel();
81 /* Release the APC lock and return */
82 KiReleaseApcLock(&ApcLock
);
86 /* Setup a Wait Block */
87 GateWaitBlock
= &Thread
->WaitBlock
[0];
88 GateWaitBlock
->Object
= (PVOID
)Gate
;
89 GateWaitBlock
->Thread
= Thread
;
91 /* Set the Thread Wait Data */
92 Thread
->WaitMode
= WaitMode
;
93 Thread
->WaitReason
= WaitReason
;
94 Thread
->WaitIrql
= ApcLock
.OldIrql
;
95 Thread
->State
= GateWait
;
96 Thread
->GateObject
= Gate
;
98 /* Insert into the Wait List */
99 InsertTailList(&Gate
->Header
.WaitListHead
,
100 &GateWaitBlock
->WaitListEntry
);
102 /* Release the gate lock */
103 KiReleaseDispatcherObject(&Gate
->Header
);
106 KiSetThreadSwapBusy(Thread
);
108 /* Release the thread lock */
109 KiReleaseThreadLock(Thread
);
111 /* Check if we had a queue */
115 KiActivateWaiterQueue(Queue
);
117 /* Release the dispatcher lock */
118 KiReleaseDispatcherLockFromDpcLevel();
121 /* Release the APC lock but stay at DPC level */
122 KiReleaseApcLockFromDpcLevel(&ApcLock
);
124 /* Find a new thread to run */
125 Status
= KiSwapThread(Thread
, KeGetCurrentPrcb());
127 /* Make sure we weren't executing an APC */
128 if (Status
== STATUS_SUCCESS
) return;
135 KeSignalGateBoostPriority(IN PKGATE Gate
)
138 PKWAIT_BLOCK WaitBlock
;
141 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
143 /* Start entry loop */
146 /* Raise to synch level */
147 OldIrql
= KeRaiseIrqlToSynchLevel();
150 KiAcquireDispatcherObject(&Gate
->Header
);
152 /* Make sure we're not already signaled or that the list is empty */
153 if (Gate
->Header
.SignalState
) break;
155 /* Check if our wait list is empty */
156 if (IsListEmpty(&Gate
->Header
.WaitListHead
))
158 /* It is, so signal the event */
159 Gate
->Header
.SignalState
= 1;
165 WaitBlock
= CONTAINING_RECORD(Gate
->Header
.WaitListHead
.Flink
,
169 /* Get the Associated thread */
170 WaitThread
= WaitBlock
->Thread
;
172 /* Check to see if the waiting thread is locked */
173 if (KiTryThreadLock(WaitThread
))
175 /* Unlock the gate */
176 KiReleaseDispatcherObject(&Gate
->Header
);
178 /* Lower IRQL and loop again */
179 KeLowerIrql(OldIrql
);
184 RemoveEntryList(&WaitBlock
->WaitListEntry
);
186 /* Clear wait status */
187 WaitThread
->WaitStatus
= STATUS_SUCCESS
;
189 /* Set state and CPU */
190 WaitThread
->State
= DeferredReady
;
191 WaitThread
->DeferredProcessor
= KeGetCurrentPrcb()->Number
;
193 /* Release the gate lock */
194 KiReleaseDispatcherObject(&Gate
->Header
);
196 /* Release the thread lock */
197 KiReleaseThreadLock(WaitThread
);
199 /* FIXME: Boosting */
201 /* Check if we have a queue */
202 if (WaitThread
->Queue
)
204 /* Acquire the dispatcher lock */
205 KiAcquireDispatcherLockAtDpcLevel();
207 /* Check if we still have one */
208 if (WaitThread
->Queue
)
210 /* Increment active threads */
211 WaitThread
->Queue
->CurrentCount
++;
215 KiReleaseDispatcherLockFromDpcLevel();
218 /* Make the thread ready */
219 KiReadyThread(WaitThread
);
221 /* Exit the dispatcher */
222 KiExitDispatcher(OldIrql
);
227 /* If we got here, then there's no rescheduling. */
228 KiReleaseDispatcherObject(&Gate
->Header
);
229 KeLowerIrql(OldIrql
);