VOID NTAPI KiAdjustQuantumThread(IN PKTHREAD Thread) { PKPRCB Prcb = KeGetCurrentPrcb(); PKTHREAD NextThread; /* Acquire thread and PRCB lock */ KiAcquireThreadLock(Thread); KiAcquirePrcbLock(Prcb); /* Don't adjust for RT threads */ if ((Thread->Priority < LOW_REALTIME_PRIORITY) && (Thread->BasePriority < (LOW_REALTIME_PRIORITY - 2))) { /* Decrease Quantum by one and see if we've ran out */ if (--Thread->Quantum <= 0) { /* Return quantum */ Thread->Quantum = Thread->QuantumReset; /* Calculate new Priority */ Thread->Priority = KiComputeNewPriority(Thread, 1); /* Check if there's no next thread scheduled */ if (!Prcb->NextThread) { /* Select a ready thread and check if we found one */ NextThread = KiSelectReadyThread(Thread->Priority, Prcb); if (NextThread) { /* Set it on standby and switch to it */ NextThread->State = Standby; Prcb->NextThread = NextThread; } } else { /* This thread can be preempted again */ Thread->Preempted = FALSE; } } } /* Release locks */ KiReleasePrcbLock(Prcb); KiReleaseThreadLock(Thread); KiExitDispatcher(Thread->WaitIrql); }
/*++ * @name KiInsertQueueApc * * The KiInsertQueueApc routine queues a APC for execution when the right * scheduler environment exists. * * @param Apc * Pointer to an initialized control object of type APC for which the * caller provides the storage. * * @param PriorityBoost * Priority Boost to apply to the Thread. * * @return None * * @remarks The APC will execute at APC_LEVEL for the KernelRoutine registered, * and at PASSIVE_LEVEL for the NormalRoutine registered. * * Callers of this routine must have locked the dipatcher database. * *--*/ VOID FASTCALL KiInsertQueueApc(IN PKAPC Apc, IN KPRIORITY PriorityBoost) { PKTHREAD Thread = Apc->Thread; PKAPC_STATE ApcState; KPROCESSOR_MODE ApcMode; PLIST_ENTRY ListHead, NextEntry; PKAPC QueuedApc; PKGATE Gate; NTSTATUS Status; BOOLEAN RequestInterrupt = FALSE; /* * Check if the caller wanted this APC to use the thread's environment at * insertion time. */ if (Apc->ApcStateIndex == InsertApcEnvironment) { /* Copy it over */ Apc->ApcStateIndex = Thread->ApcStateIndex; } /* Get the APC State for this Index, and the mode too */ ApcState = Thread->ApcStatePointer[(UCHAR)Apc->ApcStateIndex]; ApcMode = Apc->ApcMode; /* The APC must be "inserted" already */ ASSERT(Apc->Inserted == TRUE); /* Three scenarios: * 1) Kernel APC with Normal Routine or User APC = Put it at the end of the List * 2) User APC which is PsExitSpecialApc = Put it at the front of the List * 3) Kernel APC without Normal Routine = Put it at the end of the No-Normal Routine Kernel APC list */ if (Apc->NormalRoutine) { /* Normal APC; is it the Thread Termination APC? */ if ((ApcMode != KernelMode) && (Apc->KernelRoutine == PsExitSpecialApc)) { /* Set User APC pending to true */ Thread->ApcState.UserApcPending = TRUE; /* Insert it at the top of the list */ InsertHeadList(&ApcState->ApcListHead[ApcMode], &Apc->ApcListEntry); } else { /* Regular user or kernel Normal APC */ InsertTailList(&ApcState->ApcListHead[ApcMode], &Apc->ApcListEntry); } } else { /* Special APC, find the last one in the list */ ListHead = &ApcState->ApcListHead[ApcMode]; NextEntry = ListHead->Blink; while (NextEntry != ListHead) { /* Get the APC */ QueuedApc = CONTAINING_RECORD(NextEntry, KAPC, ApcListEntry); /* Is this a No-Normal APC? If so, break */ if (!QueuedApc->NormalRoutine) break; /* Move to the previous APC in the Queue */ NextEntry = NextEntry->Blink; } /* Insert us here */ InsertHeadList(NextEntry, &Apc->ApcListEntry); } /* Now check if the Apc State Indexes match */ if (Thread->ApcStateIndex == Apc->ApcStateIndex) { /* Check that the thread matches */ if (Thread == KeGetCurrentThread()) { /* Sanity check */ ASSERT(Thread->State == Running); /* Check if this is kernel mode */ if (ApcMode == KernelMode) { /* All valid, a Kernel APC is pending now */ Thread->ApcState.KernelApcPending = TRUE; /* Check if Special APCs are disabled */ if (!Thread->SpecialApcDisable) { /* They're not, so request the interrupt */ HalRequestSoftwareInterrupt(APC_LEVEL); } } } else { /* Acquire the dispatcher lock */ KiAcquireDispatcherLock(); /* Check if this is a kernel-mode APC */ if (ApcMode == KernelMode) { /* Kernel-mode APC, set us pending */ Thread->ApcState.KernelApcPending = TRUE; /* Are we currently running? */ if (Thread->State == Running) { /* The thread is running, so remember to send a request */ RequestInterrupt = TRUE; } else if ((Thread->State == Waiting) && (Thread->WaitIrql == PASSIVE_LEVEL) && !(Thread->SpecialApcDisable) && (!(Apc->NormalRoutine) || (!(Thread->KernelApcDisable) && !(Thread->ApcState.KernelApcInProgress)))) { /* We'll unwait with this status */ Status = STATUS_KERNEL_APC; /* Wake up the thread */ KiUnwaitThread(Thread, Status, PriorityBoost); } else if (Thread->State == GateWait) { /* Lock the thread */ KiAcquireThreadLock(Thread); /* Essentially do the same check as above */ if ((Thread->State == GateWait) && (Thread->WaitIrql == PASSIVE_LEVEL) && !(Thread->SpecialApcDisable) && (!(Apc->NormalRoutine) || (!(Thread->KernelApcDisable) && !(Thread->ApcState.KernelApcInProgress)))) { /* We were in a gate wait. Handle this. */ DPRINT1("A thread was in a gate wait\n"); /* Get the gate */ Gate = Thread->GateObject; /* Lock the gate */ KiAcquireDispatcherObject(&Gate->Header); /* Remove it from the waiters list */ RemoveEntryList(&Thread->WaitBlock[0].WaitListEntry); /* Unlock the gate */ KiReleaseDispatcherObject(&Gate->Header); /* Increase the queue counter if needed */ if (Thread->Queue) Thread->Queue->CurrentCount++; /* Put into deferred ready list with this status */ Thread->WaitStatus = STATUS_KERNEL_APC; KiInsertDeferredReadyList(Thread); } /* Release the thread lock */ KiReleaseThreadLock(Thread); } } else if ((Thread->State == Waiting) && (Thread->WaitMode == UserMode) && ((Thread->Alertable) || (Thread->ApcState.UserApcPending))) { /* Set user-mode APC pending */ Thread->ApcState.UserApcPending = TRUE; Status = STATUS_USER_APC; /* Wake up the thread */ KiUnwaitThread(Thread, Status, PriorityBoost); } /* Release dispatcher lock */ KiReleaseDispatcherLockFromDpcLevel(); /* Check if an interrupt was requested */ KiRequestApcInterrupt(RequestInterrupt, Thread->NextProcessor); } } }
VOID NTAPI KiQuantumEnd(VOID) { PKPRCB Prcb = KeGetCurrentPrcb(); PKTHREAD NextThread, Thread = Prcb->CurrentThread; /* Check if a DPC Event was requested to be signaled */ if (InterlockedExchange(&Prcb->DpcSetEventRequest, 0)) { /* Signal it */ KeSetEvent(&Prcb->DpcEvent, 0, 0); } /* Raise to synchronization level and lock the PRCB and thread */ KeRaiseIrqlToSynchLevel(); KiAcquireThreadLock(Thread); KiAcquirePrcbLock(Prcb); /* Check if Quantum expired */ if (Thread->Quantum <= 0) { /* Check if we're real-time and with quantums disabled */ if ((Thread->Priority >= LOW_REALTIME_PRIORITY) && (Thread->ApcState.Process->DisableQuantum)) { /* Otherwise, set maximum quantum */ Thread->Quantum = MAX_QUANTUM; } else { /* Reset the new Quantum */ Thread->Quantum = Thread->QuantumReset; /* Calculate new priority */ Thread->Priority = KiComputeNewPriority(Thread, 1); /* Check if a new thread is scheduled */ if (!Prcb->NextThread) { /* Get a new ready thread */ NextThread = KiSelectReadyThread(Thread->Priority, Prcb); if (NextThread) { /* Found one, set it on standby */ NextThread->State = Standby; Prcb->NextThread = NextThread; } } else { /* Otherwise, make sure that this thread doesn't get preempted */ Thread->Preempted = FALSE; } } } /* Release the thread lock */ KiReleaseThreadLock(Thread); /* Check if there's no thread scheduled */ if (!Prcb->NextThread) { /* Just leave now */ KiReleasePrcbLock(Prcb); KeLowerIrql(DISPATCH_LEVEL); return; } /* Get the next thread now */ NextThread = Prcb->NextThread; /* Set current thread's swap busy to true */ KiSetThreadSwapBusy(Thread); /* Switch threads in PRCB */ Prcb->NextThread = NULL; Prcb->CurrentThread = NextThread; /* Set thread to running and the switch reason to Quantum End */ NextThread->State = Running; Thread->WaitReason = WrQuantumEnd; /* Queue it on the ready lists */ KxQueueReadyThread(Thread, Prcb); /* Set wait IRQL to APC_LEVEL */ Thread->WaitIrql = APC_LEVEL; /* Swap threads */ KiSwapContext(APC_LEVEL, Thread); /* Lower IRQL back to DISPATCH_LEVEL */ KeLowerIrql(DISPATCH_LEVEL); }
VOID FASTCALL KiDeferredReadyThread(IN PKTHREAD Thread) { PKPRCB Prcb; BOOLEAN Preempted; ULONG Processor = 0; KPRIORITY OldPriority; PKTHREAD NextThread; /* Sanity checks */ ASSERT(Thread->State == DeferredReady); ASSERT((Thread->Priority >= 0) && (Thread->Priority <= HIGH_PRIORITY)); /* Check if we have any adjusts to do */ if (Thread->AdjustReason == AdjustBoost) { /* Lock the thread */ KiAcquireThreadLock(Thread); /* Check if the priority is low enough to qualify for boosting */ if ((Thread->Priority <= Thread->AdjustIncrement) && (Thread->Priority < (LOW_REALTIME_PRIORITY - 3)) && !(Thread->DisableBoost)) { /* Calculate the new priority based on the adjust increment */ OldPriority = min(Thread->AdjustIncrement + 1, LOW_REALTIME_PRIORITY - 3); /* Make sure we're not decreasing outside of the priority range */ ASSERT((Thread->PriorityDecrement >= 0) && (Thread->PriorityDecrement <= Thread->Priority)); /* Calculate the new priority decrement based on the boost */ Thread->PriorityDecrement += ((SCHAR)OldPriority - Thread->Priority); /* Again verify that this decrement is valid */ ASSERT((Thread->PriorityDecrement >= 0) && (Thread->PriorityDecrement <= OldPriority)); /* Set the new priority */ Thread->Priority = (SCHAR)OldPriority; } /* We need 4 quanta, make sure we have them, then decrease by one */ if (Thread->Quantum < 4) Thread->Quantum = 4; Thread->Quantum--; /* Make sure the priority is still valid */ ASSERT((Thread->Priority >= 0) && (Thread->Priority <= HIGH_PRIORITY)); /* Release the lock and clear the adjust reason */ KiReleaseThreadLock(Thread); Thread->AdjustReason = AdjustNone; } else if (Thread->AdjustReason == AdjustUnwait) { /* Acquire the thread lock and check if this is a real-time thread */ KiAcquireThreadLock(Thread); if (Thread->Priority < LOW_REALTIME_PRIORITY) { /* It's not real time, but is it time critical? */ if (Thread->BasePriority >= (LOW_REALTIME_PRIORITY - 2)) { /* It is, so simply reset its quantum */ Thread->Quantum = Thread->QuantumReset; } else { /* Has the priority been adjusted previously? */ if (!(Thread->PriorityDecrement) && (Thread->AdjustIncrement)) { /* Yes, reset its quantum */ Thread->Quantum = Thread->QuantumReset; } /* Wait code already handles quantum adjustment during APCs */ if (Thread->WaitStatus != STATUS_KERNEL_APC) { /* Decrease the quantum by one and check if we're out */ if (--Thread->Quantum <= 0) { /* We are, reset the quantum and get a new priority */ Thread->Quantum = Thread->QuantumReset; Thread->Priority = KiComputeNewPriority(Thread, 1); } } } /* Now check if we have no decrement and boosts are enabled */ if (!(Thread->PriorityDecrement) && !(Thread->DisableBoost)) { /* Make sure we have an increment */ ASSERT(Thread->AdjustIncrement >= 0); /* Calculate the new priority after the increment */ OldPriority = Thread->BasePriority + Thread->AdjustIncrement; /* Check if this new priority is higher */ if (OldPriority > Thread->Priority) { /* Make sure we don't go into the real time range */ if (OldPriority >= LOW_REALTIME_PRIORITY) { /* Normalize it back down one notch */ OldPriority = LOW_REALTIME_PRIORITY - 1; } /* Check if the priority is higher then the boosted base */ if (OldPriority > (Thread->BasePriority + Thread->AdjustIncrement)) { /* Setup a priority decrement to nullify the boost */ Thread->PriorityDecrement = ((SCHAR)OldPriority - Thread->BasePriority - Thread->AdjustIncrement); } /* Make sure that the priority decrement is valid */ ASSERT((Thread->PriorityDecrement >= 0) && (Thread->PriorityDecrement <= OldPriority)); /* Set this new priority */ Thread->Priority = (SCHAR)OldPriority; } } } else { /* It's a real-time thread, so just reset its quantum */ Thread->Quantum = Thread->QuantumReset; } /* Make sure the priority makes sense */ ASSERT((Thread->Priority >= 0) && (Thread->Priority <= HIGH_PRIORITY)); /* Release the thread lock and reset the adjust reason */ KiReleaseThreadLock(Thread); Thread->AdjustReason = AdjustNone; } /* Clear thread preemption status and save current values */ Preempted = Thread->Preempted; OldPriority = Thread->Priority; Thread->Preempted = FALSE; /* Queue the thread on CPU 0 and get the PRCB and lock it */ Thread->NextProcessor = 0; Prcb = KiProcessorBlock[0]; KiAcquirePrcbLock(Prcb); /* Check if we have an idle summary */ if (KiIdleSummary) { /* Clear it and set this thread as the next one */ KiIdleSummary = 0; Thread->State = Standby; Prcb->NextThread = Thread; /* Unlock the PRCB and return */ KiReleasePrcbLock(Prcb); return; } /* Set the CPU number */ Thread->NextProcessor = (UCHAR)Processor; /* Get the next scheduled thread */ NextThread = Prcb->NextThread; if (NextThread) { /* Sanity check */ ASSERT(NextThread->State == Standby); /* Check if priority changed */ if (OldPriority > NextThread->Priority) { /* Preempt the thread */ NextThread->Preempted = TRUE; /* Put this one as the next one */ Thread->State = Standby; Prcb->NextThread = Thread; /* Set it in deferred ready mode */ NextThread->State = DeferredReady; NextThread->DeferredProcessor = Prcb->Number; KiReleasePrcbLock(Prcb); KiDeferredReadyThread(NextThread); return; } } else { /* Set the next thread as the current thread */ NextThread = Prcb->CurrentThread; if (OldPriority > NextThread->Priority) { /* Preempt it if it's already running */ if (NextThread->State == Running) NextThread->Preempted = TRUE; /* Set the thread on standby and as the next thread */ Thread->State = Standby; Prcb->NextThread = Thread; /* Release the lock */ KiReleasePrcbLock(Prcb); /* Check if we're running on another CPU */ if (KeGetCurrentProcessorNumber() != Thread->NextProcessor) { /* We are, send an IPI */ KiIpiSend(AFFINITY_MASK(Thread->NextProcessor), IPI_DPC); } return; } } /* Sanity check */ ASSERT((OldPriority >= 0) && (OldPriority <= HIGH_PRIORITY)); /* Set this thread as ready */ Thread->State = Ready; Thread->WaitTime = KeTickCount.LowPart; /* Insert this thread in the appropriate order */ Preempted ? InsertHeadList(&Prcb->DispatcherReadyListHead[OldPriority], &Thread->WaitListEntry) : InsertTailList(&Prcb->DispatcherReadyListHead[OldPriority], &Thread->WaitListEntry); /* Update the ready summary */ Prcb->ReadySummary |= PRIORITY_MASK(OldPriority); /* Sanity check */ ASSERT(OldPriority == Thread->Priority); /* Release the lock */ KiReleasePrcbLock(Prcb); }
/* * @implemented */ NTSTATUS NTAPI NtYieldExecution(VOID) { NTSTATUS Status; KIRQL OldIrql; PKPRCB Prcb; PKTHREAD Thread, NextThread; /* NB: No instructions (other than entry code) should preceed this line */ /* Fail if there's no ready summary */ if (!KiGetCurrentReadySummary()) return STATUS_NO_YIELD_PERFORMED; /* Now get the current thread, set the status... */ Status = STATUS_NO_YIELD_PERFORMED; Thread = KeGetCurrentThread(); /* Raise IRQL to synch and get the KPRCB now */ OldIrql = KeRaiseIrqlToSynchLevel(); Prcb = KeGetCurrentPrcb(); /* Now check if there's still a ready summary */ if (Prcb->ReadySummary) { /* Acquire thread and PRCB lock */ KiAcquireThreadLock(Thread); KiAcquirePrcbLock(Prcb); /* Find a new thread to run if none was selected */ if (!Prcb->NextThread) Prcb->NextThread = KiSelectReadyThread(1, Prcb); /* Make sure we still have a next thread to schedule */ NextThread = Prcb->NextThread; if (NextThread) { /* Reset quantum and recalculate priority */ Thread->Quantum = Thread->QuantumReset; Thread->Priority = KiComputeNewPriority(Thread, 1); /* Release the thread lock */ KiReleaseThreadLock(Thread); /* Set context swap busy */ KiSetThreadSwapBusy(Thread); /* Set the new thread as running */ Prcb->NextThread = NULL; Prcb->CurrentThread = NextThread; NextThread->State = Running; /* Setup a yield wait and queue the thread */ Thread->WaitReason = WrYieldExecution; KxQueueReadyThread(Thread, Prcb); /* Make it wait at APC_LEVEL */ Thread->WaitIrql = APC_LEVEL; /* Sanity check */ ASSERT(OldIrql <= DISPATCH_LEVEL); /* Swap to new thread */ KiSwapContext(APC_LEVEL, Thread); Status = STATUS_SUCCESS; } else { /* Release the PRCB and thread lock */ KiReleasePrcbLock(Prcb); KiReleaseThreadLock(Thread); } } /* Lower IRQL and return */ KeLowerIrql(OldIrql); return Status; }
NTSTATUS NtYieldExecution ( VOID ) /*++ Routine Description: This function yields execution to any ready thread for up to one quantum. Arguments: None. Return Value: None. --*/ { KIRQL OldIrql; PKTHREAD NewThread; PRKPRCB Prcb; NTSTATUS Status; PKTHREAD Thread; // // If no other threads are ready, then return immediately. Otherwise, // attempt to yield execution. // // N.B. The test for ready threads is made outside any synchonization. // Since this code cannot be perfectly synchronized under any // conditions the lack of synchronization is of no consequence. // if (KiGetCurrentReadySummary() == 0) { return STATUS_NO_YIELD_PERFORMED; } else { Status = STATUS_NO_YIELD_PERFORMED; Thread = KeGetCurrentThread(); OldIrql = KeRaiseIrqlToSynchLevel(); Prcb = KeGetCurrentPrcb(); if (Prcb->ReadySummary != 0) { // // Acquire the thread lock and the PRCB lock. // // If a thread has not already been selected for execution, then // attempt to select another thread for execution. // KiAcquireThreadLock(Thread); KiAcquirePrcbLock(Prcb); if (Prcb->NextThread == NULL) { Prcb->NextThread = KiSelectReadyThread(1, Prcb); } // // If a new thread has been selected for execution, then switch // immediately to the selected thread. // if ((NewThread = Prcb->NextThread) != NULL) { Thread->Quantum = Thread->QuantumReset; // // Compute the new thread priority. // // N.B. The new priority will never be greater than the previous // priority. // Thread->Priority = KiComputeNewPriority(Thread, 1); // // Release the thread lock, set swap busy for the old thread, // set the next thread to NULL, set the current thread to the // new thread, set the new thread state to running, set the // wait reason, queue the old running thread, and release the // PRCB lock, and swp context to the new thread. // KiReleaseThreadLock(Thread); KiSetContextSwapBusy(Thread); Prcb->NextThread = NULL; Prcb->CurrentThread = NewThread; NewThread->State = Running; Thread->WaitReason = WrYieldExecution; KxQueueReadyThread(Thread, Prcb); Thread->WaitIrql = APC_LEVEL; ASSERT(OldIrql <= DISPATCH_LEVEL); KiSwapContext(Thread, NewThread); Status = STATUS_SUCCESS; } else { KiReleasePrcbLock(Prcb); KiReleaseThreadLock(Thread); } } // // Lower IRQL to its previous level and return. // KeLowerIrql(OldIrql); return Status; } }
VOID FASTCALL KeWaitForGate ( __inout PKGATE Gate, __in KWAIT_REASON WaitReason, __in KPROCESSOR_MODE WaitMode ) /*++ Routine Description: This function waits until the signal state of a gate object is set. If the state of the gate object is signaled when the wait is executed, then no wait will occur. Arguments: Gate - Supplies a pointer to a dispatcher object of type Gate. WaitReason - Supplies the reason for the wait. WaitMode - Supplies the processor mode in which the wait is to occur. Return Value: None. --*/ { PKTHREAD CurrentThread; KLOCK_QUEUE_HANDLE LockHandle; PKQUEUE Queue; PKWAIT_BLOCK WaitBlock; NTSTATUS WaitStatus; ASSERT_GATE(Gate); ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); // // Raise IRQL to SYNCH_LEVEL and acquire the APC queue lock. // CurrentThread = KeGetCurrentThread(); do { KeAcquireInStackQueuedSpinLockRaiseToSynch(&CurrentThread->ApcQueueLock, &LockHandle); // // Test to determine if a kernel APC is pending. // // If a kernel APC is pending, the special APC disable count is zero, // and the previous IRQL was less than APC_LEVEL, then a kernel APC // was queued by another processor just after IRQL was raised to // SYNCH_LEVEL, but before the APC queue lock was acquired. // // N.B. This can only happen in a multiprocessor system. // if (CurrentThread->ApcState.KernelApcPending && (CurrentThread->SpecialApcDisable == 0) && (LockHandle.OldIrql < APC_LEVEL)) { // // Unlock the APC queue lock and lower IRQL to its previous value. // An APC interrupt will immediately occur which will result in // the delivery of the kernel APC if possible. // KeReleaseInStackQueuedSpinLock(&LockHandle); continue; } // // If the current thread is associated with a queue object, then // acquire the dispatcher lock. // if ((Queue = CurrentThread->Queue) != NULL) { KiLockDispatcherDatabaseAtSynchLevel(); } // // Acquire the thread lock and the object lock. // // If the object is already signaled, then clear the signaled state, // release the object lock, release the thread lock, and lower IRQL // to its previous value. Otherwise, set the thread state to gate // wait, set the address of the gate object, insert the thread in the // object wait list, set context swap busy, release the object lock, // release the thread lock, and switch to a new thread. // KiAcquireThreadLock(CurrentThread); KiAcquireKobjectLock(Gate); if (Gate->Header.SignalState != 0) { Gate->Header.SignalState = 0; KiReleaseKobjectLock(Gate); KiReleaseThreadLock(CurrentThread); if (Queue != NULL) { KiUnlockDispatcherDatabaseFromSynchLevel(); } KeReleaseInStackQueuedSpinLock(&LockHandle); break; } else { WaitBlock = &CurrentThread->WaitBlock[0]; WaitBlock->Object = Gate; WaitBlock->Thread = CurrentThread; CurrentThread->WaitMode = WaitMode; CurrentThread->WaitReason = WaitReason; CurrentThread->WaitIrql = LockHandle.OldIrql; CurrentThread->State = GateWait; CurrentThread->GateObject = Gate; InsertTailList(&Gate->Header.WaitListHead, &WaitBlock->WaitListEntry); KiReleaseKobjectLock(Gate); KiSetContextSwapBusy(CurrentThread); KiReleaseThreadLock(CurrentThread); // // If the current thread is associated with a queue object, then // activate another thread if possible. // if (Queue != NULL) { if ((Queue = CurrentThread->Queue) != NULL) { KiActivateWaiterQueue(Queue); } KiUnlockDispatcherDatabaseFromSynchLevel(); } KeReleaseInStackQueuedSpinLockFromDpcLevel(&LockHandle); WaitStatus = (NTSTATUS)KiSwapThread(CurrentThread, KeGetCurrentPrcb()); if (WaitStatus == STATUS_SUCCESS) { return; } } } while (TRUE); return; }