Exemplo n.º 1
0
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;
    }
}
Exemplo n.º 2
0
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;
}