Exemple #1
0
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);
}
Exemple #2
0
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);
}
Exemple #3
0
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;
}