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