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 Gate
->Header
.Type
= GateObject
;
23 Gate
->Header
.Signalling
= FALSE
;
24 Gate
->Header
.Size
= sizeof(KGATE
) / sizeof(ULONG
);
25 Gate
->Header
.SignalState
= 0;
26 InitializeListHead(&(Gate
->Header
.WaitListHead
));
31 KeWaitForGate(IN PKGATE Gate
,
32 IN KWAIT_REASON WaitReason
,
33 IN KPROCESSOR_MODE WaitMode
)
35 KLOCK_QUEUE_HANDLE ApcLock
;
36 PKTHREAD Thread
= KeGetCurrentThread();
37 PKWAIT_BLOCK GateWaitBlock
;
41 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
46 /* Acquire the APC lock */
47 KiAcquireApcLock(Thread
, &ApcLock
);
49 /* Check if a kernel APC is pending and we're below APC_LEVEL */
50 if ((Thread
->ApcState
.KernelApcPending
) &&
51 !(Thread
->SpecialApcDisable
) &&
52 (ApcLock
.OldIrql
< APC_LEVEL
))
54 /* Release the lock, this will fire the APC */
55 KiReleaseApcLock(&ApcLock
);
59 /* Check if we have a queue and lock the dispatcher if so */
60 Queue
= Thread
->Queue
;
61 if (Queue
) KiAcquireDispatcherLockAtDpcLevel();
64 KiAcquireThreadLock(Thread
);
67 KiAcquireDispatcherObject(&Gate
->Header
);
69 /* Check if it's already signaled */
70 if (Gate
->Header
.SignalState
)
73 Gate
->Header
.SignalState
= 0;
75 /* Release the gate and thread locks */
76 KiReleaseDispatcherObject(&Gate
->Header
);
77 KiReleaseThreadLock(Thread
);
79 /* Release the gate lock */
80 if (Queue
) KiReleaseDispatcherLockFromDpcLevel();
82 /* Release the APC lock and return */
83 KiReleaseApcLock(&ApcLock
);
87 /* Setup a Wait Block */
88 GateWaitBlock
= &Thread
->WaitBlock
[0];
89 GateWaitBlock
->Object
= (PVOID
)Gate
;
90 GateWaitBlock
->Thread
= Thread
;
92 /* Set the Thread Wait Data */
93 Thread
->WaitMode
= WaitMode
;
94 Thread
->WaitReason
= WaitReason
;
95 Thread
->WaitIrql
= ApcLock
.OldIrql
;
96 Thread
->State
= GateWait
;
97 Thread
->GateObject
= Gate
;
99 /* Insert into the Wait List */
100 InsertTailList(&Gate
->Header
.WaitListHead
,
101 &GateWaitBlock
->WaitListEntry
);
103 /* Release the gate lock */
104 KiReleaseDispatcherObject(&Gate
->Header
);
107 KiSetThreadSwapBusy(Thread
);
109 /* Release the thread lock */
110 KiReleaseThreadLock(Thread
);
112 /* Check if we had a queue */
116 KiActivateWaiterQueue(Queue
);
118 /* Release the dispatcher lock */
119 KiReleaseDispatcherLockFromDpcLevel();
122 /* Release the APC lock but stay at DPC level */
123 KiReleaseApcLockFromDpcLevel(&ApcLock
);
125 /* Find a new thread to run */
126 Status
= KiSwapThread(Thread
, KeGetCurrentPrcb());
128 /* Make sure we weren't executing an APC */
129 if (Status
== STATUS_SUCCESS
) return;
136 KeSignalGateBoostPriority(IN PKGATE Gate
)
139 PKWAIT_BLOCK WaitBlock
;
142 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
144 /* Start entry loop */
147 /* Raise to synch level */
148 OldIrql
= KeRaiseIrqlToSynchLevel();
151 KiAcquireDispatcherObject(&Gate
->Header
);
153 /* Make sure we're not already signaled or that the list is empty */
154 if (Gate
->Header
.SignalState
) break;
156 /* Check if our wait list is empty */
157 if (IsListEmpty(&Gate
->Header
.WaitListHead
))
159 /* It is, so signal the event */
160 Gate
->Header
.SignalState
= 1;
166 WaitBlock
= CONTAINING_RECORD(Gate
->Header
.WaitListHead
.Flink
,
170 /* Get the Associated thread */
171 WaitThread
= WaitBlock
->Thread
;
173 /* Check to see if the waiting thread is locked */
174 if (KiTryThreadLock(WaitThread
))
176 /* Unlock the gate */
177 KiReleaseDispatcherObject(&Gate
->Header
);
179 /* Lower IRQL and loop again */
180 KeLowerIrql(OldIrql
);
185 RemoveEntryList(&WaitBlock
->WaitListEntry
);
187 /* Clear wait status */
188 WaitThread
->WaitStatus
= STATUS_SUCCESS
;
190 /* Set state and CPU */
191 WaitThread
->State
= DeferredReady
;
192 WaitThread
->DeferredProcessor
= KeGetCurrentPrcb()->Number
;
194 /* Release the gate lock */
195 KiReleaseDispatcherObject(&Gate
->Header
);
197 /* Release the thread lock */
198 KiReleaseThreadLock(WaitThread
);
200 /* FIXME: Boosting */
202 /* Check if we have a queue */
203 if (WaitThread
->Queue
)
205 /* Acquire the dispatcher lock */
206 KiAcquireDispatcherLockAtDpcLevel();
208 /* Check if we still have one */
209 if (WaitThread
->Queue
)
211 /* Increment active threads */
212 WaitThread
->Queue
->CurrentCount
++;
216 KiReleaseDispatcherLockFromDpcLevel();
219 /* Make the thread ready */
220 KiReadyThread(WaitThread
);
222 /* Exit the dispatcher */
223 KiExitDispatcher(OldIrql
);
228 /* If we got here, then there's no rescheduling. */
229 KiReleaseDispatcherObject(&Gate
->Header
);
230 KeLowerIrql(OldIrql
);