Esempio n. 1
0
File: apc.c Progetto: GYGit/reactos
/*++
 * @name KiCheckForKernelApcDelivery
 * @implemented NT 5.2
 *
 *     The KiCheckForKernelApcDelivery routine is called whenever APCs have
 *     just been re-enabled in Kernel Mode, such as after leaving a Critical or
 *     Guarded Region. It delivers APCs if the environment is right.
 *
 * @param None.
 *
 * @return None.
 *
 * @remarks This routine allows KeLeave/EnterCritical/GuardedRegion to be used
 *          as macros from inside WIN32K or other Drivers, which will then only
 *          have to do an Import API call in the case where APCs are enabled again.
 *
 *--*/
VOID
NTAPI
KiCheckForKernelApcDelivery(VOID)
{
    KIRQL OldIrql;

    /* We should only deliver at passive */
    if (KeGetCurrentIrql() == PASSIVE_LEVEL)
    {
        /* Raise to APC and Deliver APCs, then lower back to Passive */
        KeRaiseIrql(APC_LEVEL, &OldIrql);
        KiDeliverApc(KernelMode, 0, 0);
        KeLowerIrql(PASSIVE_LEVEL);
    }
    else
    {
        /*
         * If we're not at passive level it means someone raised IRQL
         * to APC level before the critical or guarded section was entered
         * (e.g) by a fast mutex). This implies that the APCs shouldn't
         * be delivered now, but after the IRQL is lowered to passive
         * level again.
         */
        KeGetCurrentThread()->ApcState.KernelApcPending = TRUE;
        HalRequestSoftwareInterrupt(APC_LEVEL);
    }
}
Esempio n. 2
0
VOID
FASTCALL
KiCompleteTimer(IN PKTIMER Timer,
                IN PKSPIN_LOCK_QUEUE LockQueue)
{
    LIST_ENTRY ListHead;
    BOOLEAN RequestInterrupt = FALSE;
    DPRINT("KiCompleteTimer(): Timer %p, LockQueue: %p\n", Timer, LockQueue);

    /* Remove it from the timer list */
    KiRemoveEntryTimer(Timer);

    /* Link the timer list to our stack */
    ListHead.Flink = &Timer->TimerListEntry;
    ListHead.Blink = &Timer->TimerListEntry;
    Timer->TimerListEntry.Flink = &ListHead;
    Timer->TimerListEntry.Blink = &ListHead;

    /* Release the timer lock */
    KiReleaseTimerLock(LockQueue);

    /* Acquire dispatcher lock */
    KiAcquireDispatcherLockAtDpcLevel();

    /* Signal the timer if it's still on our list */
    if (!IsListEmpty(&ListHead)) RequestInterrupt = KiSignalTimer(Timer);

    /* Release the dispatcher lock */
    KiReleaseDispatcherLockFromDpcLevel();

    /* Request a DPC if needed */
    if (RequestInterrupt) HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
}
Esempio n. 3
0
BOOLEAN
FASTCALL
KiSwapContextExit(IN PKTHREAD OldThread,
                  IN PKSWITCHFRAME SwitchFrame)
{
    PKIPCR Pcr = (PKIPCR)KeGetPcr();
    PKPROCESS OldProcess, NewProcess;
    PKTHREAD NewThread;
    ARM_TTB_REGISTER TtbRegister;

    /* We are on the new thread stack now */
    NewThread = Pcr->PrcbData.CurrentThread;

    /* Now we are the new thread. Check if it's in a new process */
    OldProcess = OldThread->ApcState.Process;
    NewProcess = NewThread->ApcState.Process;
    if (OldProcess != NewProcess)
    {
        TtbRegister.AsUlong = NewProcess->DirectoryTableBase[0];
        ASSERT(TtbRegister.Reserved == 0);
        KeArmTranslationTableRegisterSet(TtbRegister);
    }

    /* Increase thread context switches */
    NewThread->ContextSwitches++;

    /* Load data from switch frame */
    Pcr->NtTib.ExceptionList = SwitchFrame->ExceptionList;

    /* DPCs shouldn't be active */
    if (Pcr->PrcbData.DpcRoutineActive)
    {
        /* Crash the machine */
        KeBugCheckEx(ATTEMPTED_SWITCH_FROM_DPC,
                     (ULONG_PTR)OldThread,
                     (ULONG_PTR)NewThread,
                     (ULONG_PTR)OldThread->InitialStack,
                     0);
    }

    /* Kernel APCs may be pending */
    if (NewThread->ApcState.KernelApcPending)
    {
        /* Are APCs enabled? */
        if (!NewThread->SpecialApcDisable)
        {
            /* Request APC delivery */
            if (SwitchFrame->ApcBypassDisable) HalRequestSoftwareInterrupt(APC_LEVEL);
            return TRUE;
        }
    }

    /* Return */
    return FALSE;
}
Esempio n. 4
0
// ******************************************************************
// * 0x00A3 - KiUnlockDispatcherDatabase()
// ******************************************************************
XBSYSAPI EXPORTNUM(163) xboxkrnl::VOID FASTCALL xboxkrnl::KiUnlockDispatcherDatabase
(
	IN KIRQL OldIrql
)
{
	LOG_FUNC_ONE_ARG_TYPE(KIRQL_TYPE, OldIrql);

	if (!(KeGetCurrentPrcb()->DpcRoutineActive)) // Avoid KeIsExecutingDpc(), as that logs
		HalRequestSoftwareInterrupt(DISPATCH_LEVEL);

	LOG_INCOMPLETE(); // TODO : Thread-switch?

	KfLowerIrql(OldIrql);
}
Esempio n. 5
0
/*
 * @implemented
 */
BOOLEAN
NTAPI
KeSetTimerEx(IN OUT PKTIMER Timer,
             IN LARGE_INTEGER DueTime,
             IN LONG Period,
             IN PKDPC Dpc OPTIONAL)
{
    KIRQL OldIrql;
    BOOLEAN Inserted;
    ULONG Hand = 0;
    BOOLEAN RequestInterrupt = FALSE;
    ASSERT_TIMER(Timer);
    ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
    DPRINT("KeSetTimerEx(): Timer %p, DueTime %I64d, Period %d, Dpc %p\n",
           Timer, DueTime.QuadPart, Period, Dpc);

    /* Lock the Database and Raise IRQL */
    OldIrql = KiAcquireDispatcherLock();

    /* Check if it's inserted, and remove it if it is */
    Inserted = Timer->Header.Inserted;
    if (Inserted) KxRemoveTreeTimer(Timer);

    /* Set Default Timer Data */
    Timer->Dpc = Dpc;
    Timer->Period = Period;
    if (!KiComputeDueTime(Timer, DueTime, &Hand))
    {
        /* Signal the timer */
        RequestInterrupt = KiSignalTimer(Timer);
        
        /* Release the dispatcher lock */
        KiReleaseDispatcherLockFromDpcLevel();
        
        /* Check if we need to do an interrupt */
        if (RequestInterrupt) HalRequestSoftwareInterrupt(DISPATCH_LEVEL);        
    }
    else
    {
        /* Insert the timer */
        Timer->Header.SignalState = FALSE;
        KxInsertTimer(Timer, Hand);        
    }
    
    /* Exit the dispatcher */
    KiExitDispatcher(OldIrql);

    /* Return old state */
    return Inserted;
}
Esempio n. 6
0
File: time.c Progetto: GYGit/reactos
FORCEINLINE
VOID
KiCheckForTimerExpiration(
    PKPRCB Prcb,
    PKTRAP_FRAME TrapFrame,
    ULARGE_INTEGER InterruptTime)
{
    ULONG Hand;

    /* Check for timer expiration */
    Hand = KeTickCount.LowPart & (TIMER_TABLE_SIZE - 1);
    if (KiTimerTableListHead[Hand].Time.QuadPart <= InterruptTime.QuadPart)
    {
        /* Check if we are already doing expiration */
        if (!Prcb->TimerRequest)
        {
            /* Request a DPC to handle this */
            Prcb->TimerRequest = (ULONG_PTR)TrapFrame;
            Prcb->TimerHand = Hand;
            HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
        }
    }
}
Esempio n. 7
0
/*
 * @implemented
 */
VOID
NTAPI
KeFlushQueuedDpcs(VOID)
{
    PKPRCB CurrentPrcb = KeGetCurrentPrcb();
    PAGED_CODE();

    /* Check if this is an UP machine */
    if (KeActiveProcessors == 1)
    {
        /* Check if there are DPCs on either queues */
        if ((CurrentPrcb->DpcData[DPC_NORMAL].DpcQueueDepth > 0) ||
            (CurrentPrcb->DpcData[DPC_THREADED].DpcQueueDepth > 0))
        {
            /* Request an interrupt */
            HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
        }
    }
    else
    {
        /* FIXME: SMP support required */
        ASSERT(FALSE);
    }
}
Esempio n. 8
0
File: time.c Progetto: GYGit/reactos
VOID
NTAPI
KeUpdateRunTime(IN PKTRAP_FRAME TrapFrame,
                IN KIRQL Irql)
{
    PKTHREAD Thread = KeGetCurrentThread();
    PKPRCB Prcb = KeGetCurrentPrcb();

    /* Check if this tick is being skipped */
    if (Prcb->SkipTick)
    {
        /* Handle it next time */
        Prcb->SkipTick = FALSE;
        return;
    }

    /* Increase interrupt count */
    Prcb->InterruptCount++;

    /* Check if we came from user mode */
#ifndef _M_ARM
    if (KiUserTrap(TrapFrame) || (TrapFrame->EFlags & EFLAGS_V86_MASK))
#else
    if (TrapFrame->PreviousMode == UserMode)
#endif
    {
        /* Increase thread user time */
        Prcb->UserTime++;
        Thread->UserTime++;
    }
    else
    {
        /* See if we were in an ISR */
        Prcb->KernelTime++;
        if (Irql > DISPATCH_LEVEL)
        {
            /* Handle that */
            Prcb->InterruptTime++;
        }
        else if ((Irql < DISPATCH_LEVEL) || !(Prcb->DpcRoutineActive))
        {
            /* Handle being in kernel mode */
            Thread->KernelTime++;
        }
        else
        {
            /* Handle being in a DPC */
            Prcb->DpcTime++;

#if DBG
            /* Update the DPC time */
            Prcb->DebugDpcTime++;

            /* Check if we have timed out */
            if (Prcb->DebugDpcTime == KiDPCTimeout)
            {
                /* We did! */
                DbgPrint("*** DPC routine > 1 sec --- This is not a break in KeUpdateSystemTime\n");

                /* Break if debugger is enabled */
                if (KdDebuggerEnabled) DbgBreakPoint();

                /* Clear state */
                Prcb->DebugDpcTime = 0;
            }
#endif
        }
    }

    /* Update DPC rates */
    Prcb->DpcRequestRate = ((Prcb->DpcData[0].DpcCount - Prcb->DpcLastCount) +
                            Prcb->DpcRequestRate) >> 1;
    Prcb->DpcLastCount = Prcb->DpcData[0].DpcCount;

    /* Check if the queue is large enough */
    if ((Prcb->DpcData[0].DpcQueueDepth) && !(Prcb->DpcRoutineActive))
    {
        /* Request a DPC */
        Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold;
        HalRequestSoftwareInterrupt(DISPATCH_LEVEL);

        /* Fix the maximum queue depth */
        if ((Prcb->DpcRequestRate < KiIdealDpcRate) &&
            (Prcb->MaximumDpcQueueDepth > 1))
        {
            /* Make it smaller */
            Prcb->MaximumDpcQueueDepth--;
        }
    }
    else
    {
        /* Check if we've reached the adjustment limit */
        if (!(--Prcb->AdjustDpcThreshold))
        {
            /* Reset it, and check the queue maximum */
            Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold;
            if (KiMaximumDpcQueueDepth != Prcb->MaximumDpcQueueDepth)
            {
                /* Increase it */
                Prcb->MaximumDpcQueueDepth++;
            }
        }
    }

    /* Decrement the thread quantum */
    Thread->Quantum -= CLOCK_QUANTUM_DECREMENT;

    /* Check if the time expired */
    if ((Thread->Quantum <= 0) && (Thread != Prcb->IdleThread))
    {
        /* Schedule a quantum end */
        Prcb->QuantumEnd = 1;
        HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
    }
}
Esempio n. 9
0
File: apc.c Progetto: GYGit/reactos
/*++
 * @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);
        }
    }
}
Esempio n. 10
0
/*
 * @implemented
 */
BOOLEAN
NTAPI
KeInsertQueueDpc(IN PKDPC Dpc,
                 IN PVOID SystemArgument1,
                 IN PVOID SystemArgument2)
{
    KIRQL OldIrql;
    PKPRCB Prcb, CurrentPrcb;
    ULONG Cpu;
    PKDPC_DATA DpcData;
    BOOLEAN DpcConfigured = FALSE, DpcInserted = FALSE;
    ASSERT_DPC(Dpc);

    /* Check IRQL and Raise it to HIGH_LEVEL */
    KeRaiseIrql(HIGH_LEVEL, &OldIrql);
    CurrentPrcb = KeGetCurrentPrcb();

    /* Check if the DPC has more then the maximum number of CPUs */
    if (Dpc->Number >= MAXIMUM_PROCESSORS)
    {
        /* Then substract the maximum and get that PRCB. */
        Cpu = Dpc->Number - MAXIMUM_PROCESSORS;
        Prcb = KiProcessorBlock[Cpu];
    }
    else
    {
        /* Use the current one */
        Prcb = CurrentPrcb;
        Cpu = Prcb->Number;
    }

    /* ROS Sanity Check */
    ASSERT(Prcb == CurrentPrcb);

    /* Check if this is a threaded DPC and threaded DPCs are enabled */
    if ((Dpc->Type == ThreadedDpcObject) && (Prcb->ThreadDpcEnable))
    {
        /* Then use the threaded data */
        DpcData = &Prcb->DpcData[DPC_THREADED];
    }
    else
    {
        /* Otherwise, use the regular data */
        DpcData = &Prcb->DpcData[DPC_NORMAL];
    }

    /* Acquire the DPC lock */
    KiAcquireSpinLock(&DpcData->DpcLock);

    /* Get the DPC Data */
    if (!InterlockedCompareExchangePointer(&Dpc->DpcData, DpcData, NULL))
    {
        /* Now we can play with the DPC safely */
        Dpc->SystemArgument1 = SystemArgument1;
        Dpc->SystemArgument2 = SystemArgument2;
        DpcData->DpcQueueDepth++;
        DpcData->DpcCount++;
        DpcConfigured = TRUE;

        /* Check if this is a high importance DPC */
        if (Dpc->Importance == HighImportance)
        {
            /* Pre-empty other DPCs */
            InsertHeadList(&DpcData->DpcListHead, &Dpc->DpcListEntry);
        }
        else
        {
            /* Add it at the end */
            InsertTailList(&DpcData->DpcListHead, &Dpc->DpcListEntry);
        }

        /* Check if this is the DPC on the threaded list */
        if (&Prcb->DpcData[DPC_THREADED] == DpcData)
        {
            /* Make sure a threaded DPC isn't already active */
            if (!(Prcb->DpcThreadActive) && !(Prcb->DpcThreadRequested))
            {
                /* FIXME: Setup Threaded DPC */
                DPRINT1("Threaded DPC not supported\n");
                while (TRUE);
            }
        }
        else
        {
            /* Make sure a DPC isn't executing already */
            if (!(Prcb->DpcRoutineActive) && !(Prcb->DpcInterruptRequested))
            {
                /* Check if this is the same CPU */
                if (Prcb != CurrentPrcb)
                {
                    /*
                     * Check if the DPC is of high importance or above the
                     * maximum depth. If it is, then make sure that the CPU
                     * isn't idle, or that it's sleeping.
                     */
                    if (((Dpc->Importance == HighImportance) ||
                        (DpcData->DpcQueueDepth >=
                         Prcb->MaximumDpcQueueDepth)) &&
                        (!(AFFINITY_MASK(Cpu) & KiIdleSummary) ||
                         (Prcb->Sleeping)))
                    {
                        /* Set interrupt requested */
                        Prcb->DpcInterruptRequested = TRUE;

                        /* Set DPC inserted */
                        DpcInserted = TRUE;
                    }
                }
                else
                {
                    /* Check if the DPC is of anything but low importance */
                    if ((Dpc->Importance != LowImportance) ||
                        (DpcData->DpcQueueDepth >=
                         Prcb->MaximumDpcQueueDepth) ||
                        (Prcb->DpcRequestRate < Prcb->MinimumDpcRate))
                    {
                        /* Set interrupt requested */
                        Prcb->DpcInterruptRequested = TRUE;

                        /* Set DPC inserted */
                        DpcInserted = TRUE;
                    }
                }
            }
        }
    }

    /* Release the lock */
    KiReleaseSpinLock(&DpcData->DpcLock);

    /* Check if the DPC was inserted */
    if (DpcInserted)
    {
        /* Check if this was SMP */
        if (Prcb != CurrentPrcb)
        {
            /* It was, request and IPI */
            KiIpiSend(AFFINITY_MASK(Cpu), IPI_DPC);
        }
        else
        {
            /* It wasn't, request an interrupt from HAL */
            HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
        }
    }

    /* Lower IRQL */
    KeLowerIrql(OldIrql);
    return DpcConfigured;
}