xref: /reactos/ntoskrnl/ke/gate.c (revision 7523a7b1)
1 /*
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)
7  */
8 
9 /* INCLUDES *****************************************************************/
10 
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14 
15 /* FUNCTIONS ****************************************************************/
16 
17 VOID
18 FASTCALL
KeInitializeGate(IN PKGATE Gate)19 KeInitializeGate(IN PKGATE Gate)
20 {
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));
27 }
28 
29 VOID
30 FASTCALL
KeWaitForGate(IN PKGATE Gate,IN KWAIT_REASON WaitReason,IN KPROCESSOR_MODE WaitMode)31 KeWaitForGate(IN PKGATE Gate,
32               IN KWAIT_REASON WaitReason,
33               IN KPROCESSOR_MODE WaitMode)
34 {
35     KLOCK_QUEUE_HANDLE ApcLock;
36     PKTHREAD Thread = KeGetCurrentThread();
37     PKWAIT_BLOCK GateWaitBlock;
38     LONG_PTR Status;
39     PKQUEUE Queue;
40     ASSERT_GATE(Gate);
41     ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
42 
43     /* Start wait loop */
44     do
45     {
46         /* Acquire the APC lock */
47         KiAcquireApcLockRaiseToSynch(Thread, &ApcLock);
48 
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))
53         {
54             /* Release the lock, this will fire the APC */
55             KiReleaseApcLock(&ApcLock);
56         }
57         else
58         {
59             /* Check if we have a queue and lock the dispatcher if so */
60             Queue = Thread->Queue;
61             if (Queue) KiAcquireDispatcherLockAtSynchLevel();
62 
63             /* Lock the thread */
64             KiAcquireThreadLock(Thread);
65 
66             /* Lock the gate */
67             KiAcquireDispatcherObject(&Gate->Header);
68 
69             /* Check if it's already signaled */
70             if (Gate->Header.SignalState)
71             {
72                 /* Unsignal it */
73                 Gate->Header.SignalState = 0;
74 
75                 /* Release the gate and thread locks */
76                 KiReleaseDispatcherObject(&Gate->Header);
77                 KiReleaseThreadLock(Thread);
78 
79                 /* Release the gate lock */
80                 if (Queue) KiReleaseDispatcherLockFromSynchLevel();
81 
82                 /* Release the APC lock and return */
83                 KiReleaseApcLock(&ApcLock);
84                 break;
85             }
86 
87             /* Setup a Wait Block */
88             GateWaitBlock = &Thread->WaitBlock[0];
89             GateWaitBlock->Object = (PVOID)Gate;
90             GateWaitBlock->Thread = Thread;
91 
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;
98 
99             /* Insert into the Wait List */
100             InsertTailList(&Gate->Header.WaitListHead,
101                            &GateWaitBlock->WaitListEntry);
102 
103             /* Release the gate lock */
104             KiReleaseDispatcherObject(&Gate->Header);
105 
106             /* Set swap busy */
107             KiSetThreadSwapBusy(Thread);
108 
109             /* Release the thread lock */
110             KiReleaseThreadLock(Thread);
111 
112             /* Check if we had a queue */
113             if (Queue)
114             {
115                 /* Wake it up */
116                 KiActivateWaiterQueue(Queue);
117 
118                 /* Release the dispatcher lock */
119                 KiReleaseDispatcherLockFromSynchLevel();
120             }
121 
122             /* Release the APC lock but stay at DPC level */
123             KiReleaseApcLockFromSynchLevel(&ApcLock);
124 
125             /* Find a new thread to run */
126             Status = KiSwapThread(Thread, KeGetCurrentPrcb());
127 
128             /* Make sure we weren't executing an APC */
129             if (Status == STATUS_SUCCESS) return;
130         }
131     } while (TRUE);
132 }
133 
134 VOID
135 FASTCALL
KeSignalGateBoostPriority(IN PKGATE Gate)136 KeSignalGateBoostPriority(IN PKGATE Gate)
137 {
138     PKTHREAD WaitThread;
139     PKWAIT_BLOCK WaitBlock;
140     KIRQL OldIrql;
141     ASSERT_GATE(Gate);
142     ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
143 
144     /* Start entry loop */
145     for (;;)
146     {
147         /* Raise to synch level */
148         OldIrql = KeRaiseIrqlToSynchLevel();
149 
150         /* Lock the gate */
151         KiAcquireDispatcherObject(&Gate->Header);
152 
153         /* Make sure we're not already signaled or that the list is empty */
154         if (Gate->Header.SignalState) break;
155 
156         /* Check if our wait list is empty */
157         if (IsListEmpty(&Gate->Header.WaitListHead))
158         {
159             /* It is, so signal the event */
160             Gate->Header.SignalState = 1;
161             break;
162         }
163         else
164         {
165             /* Get WaitBlock */
166             WaitBlock = CONTAINING_RECORD(Gate->Header.WaitListHead.Flink,
167                                           KWAIT_BLOCK,
168                                           WaitListEntry);
169 
170             /* Get the Associated thread */
171             WaitThread = WaitBlock->Thread;
172 
173             /* Check to see if the waiting thread is locked */
174             if (KiTryThreadLock(WaitThread))
175             {
176                 /* Unlock the gate */
177                 KiReleaseDispatcherObject(&Gate->Header);
178 
179                 /* Lower IRQL and loop again */
180                 KeLowerIrql(OldIrql);
181                 continue;
182             }
183 
184             /* Remove it */
185             RemoveEntryList(&WaitBlock->WaitListEntry);
186 
187             /* Clear wait status */
188             WaitThread->WaitStatus = STATUS_SUCCESS;
189 
190             /* Set state and CPU */
191             WaitThread->State = DeferredReady;
192             WaitThread->DeferredProcessor = KeGetCurrentPrcb()->Number;
193 
194             /* Release the gate lock */
195             KiReleaseDispatcherObject(&Gate->Header);
196 
197             /* Release the thread lock */
198             KiReleaseThreadLock(WaitThread);
199 
200             /* FIXME: Boosting */
201 
202             /* Check if we have a queue */
203             if (WaitThread->Queue)
204             {
205                 /* Acquire the dispatcher lock */
206                 KiAcquireDispatcherLockAtSynchLevel();
207 
208                 /* Check if we still have one */
209                 if (WaitThread->Queue)
210                 {
211                     /* Increment active threads */
212                     WaitThread->Queue->CurrentCount++;
213                 }
214 
215                 /* Release lock */
216                 KiReleaseDispatcherLockFromSynchLevel();
217             }
218 
219             /* Make the thread ready */
220             KiReadyThread(WaitThread);
221 
222             /* Exit the dispatcher */
223             KiExitDispatcher(OldIrql);
224             return;
225         }
226     }
227 
228     /* If we got here, then there's no rescheduling. */
229     KiReleaseDispatcherObject(&Gate->Header);
230     KeLowerIrql(OldIrql);
231 }
232 
233 /* EOF */
234