VOID FASTCALL KiProcessDeferredReadyList(IN PKPRCB Prcb) { PSINGLE_LIST_ENTRY ListEntry; PKTHREAD Thread; /* Make sure there is something on the ready list */ ASSERT(Prcb->DeferredReadyListHead.Next != NULL); /* Get the first entry and clear the list */ ListEntry = Prcb->DeferredReadyListHead.Next; Prcb->DeferredReadyListHead.Next = NULL; /* Start processing loop */ do { /* Get the thread and advance to the next entry */ Thread = CONTAINING_RECORD(ListEntry, KTHREAD, SwapListEntry); ListEntry = ListEntry->Next; /* Make the thread ready */ KiDeferredReadyThread(Thread); } while (ListEntry != NULL); /* Make sure the ready list is still empty */ ASSERT(Prcb->DeferredReadyListHead.Next == NULL); }
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); }
VOID FASTCALL KeSignalGateBoostPriority ( __inout PKGATE Gate ) /*++ Routine Description: This function conditionally sets the signal state of a gate object and attempts to unwait the first waiter. Arguments: Gate - Supplies a pointer to a dispatcher object of type gate. Return Value: None. --*/ { PKTHREAD CurrentThread; PLIST_ENTRY Entry; KIRQL OldIrql; SCHAR Priority; PKQUEUE Queue; PKWAIT_BLOCK WaitBlock; PKTHREAD WaitThread; ASSERT_GATE(Gate); ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); // // Raise IRQL to SYNCH_LEVEL and acquire the object lock. // // If the object is not already signaled, then attempt to wake a waiter. // CurrentThread = KeGetCurrentThread(); do { OldIrql = KeRaiseIrqlToSynchLevel(); KiAcquireKobjectLock(Gate); if (Gate->Header.SignalState == 0) { // // If there are any waiters, then remove and ready the first // waiter. Otherwise, set the signal state. // if (IsListEmpty(&Gate->Header.WaitListHead) == FALSE) { Entry = Gate->Header.WaitListHead.Flink; WaitBlock = CONTAINING_RECORD(Entry, KWAIT_BLOCK, WaitListEntry); WaitThread = WaitBlock->Thread; // // Try to acquire the thread lock. // // If the thread lock cannot be acquired, then release the // object lock, lower IRQL to is previous value, and try to // signal the gate again. Otherwise, remove the entry from // the list, set the wait completion status to success, set // the deferred processor number, set the thread state to // deferred ready, release the thread lock, release the // object lock, compute the new thread priority, ready the // thread for execution, and exit the dispatcher. // if (KiTryToAcquireThreadLock(WaitThread)) { RemoveEntryList(Entry); WaitThread->WaitStatus = STATUS_SUCCESS; WaitThread->State = DeferredReady; WaitThread->DeferredProcessor = KeGetCurrentPrcb()->Number; KiReleaseKobjectLock(Gate); KiReleaseThreadLock(WaitThread); Priority = CurrentThread->Priority; if (Priority < LOW_REALTIME_PRIORITY) { Priority = Priority - CurrentThread->PriorityDecrement; if (Priority < CurrentThread->BasePriority) { Priority = CurrentThread->BasePriority; } if (CurrentThread->PriorityDecrement != 0) { CurrentThread->PriorityDecrement = 0; CurrentThread->Quantum = CLOCK_QUANTUM_DECREMENT; } } WaitThread->AdjustIncrement = Priority; WaitThread->AdjustReason = (UCHAR)AdjustBoost; // // If the wait thread is associated with a queue, then // increment the concurrency level. // // N.B. This can be done after dropping all other locks, // but must be done holding the dispatcher lock // since the concurrency count is not accessed with // interlocked operations elsewhere. // if (WaitThread->Queue != NULL) { KiLockDispatcherDatabaseAtSynchLevel(); if ((Queue = WaitThread->Queue) != NULL) { Queue->CurrentCount += 1; } KiUnlockDispatcherDatabaseFromSynchLevel(); } KiDeferredReadyThread(WaitThread); KiExitDispatcher(OldIrql); return; } else { KiReleaseKobjectLock(Gate); KeLowerIrql(OldIrql); continue; } } else { Gate->Header.SignalState = 1; break; } } else { break; } } while (TRUE); // // Release the object lock and lower IRQL to its previous value. // KiReleaseKobjectLock(Gate); KeLowerIrql(OldIrql); return; }