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 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 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 KiAcquireApcLock(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) KiAcquireDispatcherLockAtDpcLevel(); 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) KiReleaseDispatcherLockFromDpcLevel(); 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 KiReleaseDispatcherLockFromDpcLevel(); 120 } 121 122 /* Release the APC lock but stay at DPC level */ 123 KiReleaseApcLockFromDpcLevel(&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 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 KiAcquireDispatcherLockAtDpcLevel(); 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 KiReleaseDispatcherLockFromDpcLevel(); 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