Example #1
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);
}
Example #2
0
BOOLEAN
FASTCALL
KiInsertTreeTimer(IN PKTIMER Timer,
                  IN LARGE_INTEGER Interval)
{
    BOOLEAN Inserted = FALSE;
    ULONG Hand = 0;
    PKSPIN_LOCK_QUEUE LockQueue;
    DPRINT("KiInsertTreeTimer(): Timer %p, Interval: %I64d\n", Timer, Interval.QuadPart);

    /* Setup the timer's due time */
    if (KiComputeDueTime(Timer, Interval, &Hand))
    {
        /* Acquire the lock */
        LockQueue = KiAcquireTimerLock(Hand);

        /* Insert the timer */
        if (KiInsertTimerTable(Timer, Hand))
        {
            /* It was already there, remove it */
            KiRemoveEntryTimer(Timer);
            Timer->Header.Inserted = FALSE;
        }
        else
        {
            /* Otherwise, we're now inserted */
            Inserted = TRUE;
        }
        
        /* Release the lock */
        KiReleaseTimerLock(LockQueue);
    }

    /* Release the lock and return insert status */
    return Inserted;
}
Example #3
0
VOID
NTAPI
KiTimerExpiration(IN PKDPC Dpc,
                  IN PVOID DeferredContext,
                  IN PVOID SystemArgument1,
                  IN PVOID SystemArgument2)
{
    ULARGE_INTEGER SystemTime, InterruptTime;
    LARGE_INTEGER Interval;
    LONG Limit, Index, i;
    ULONG Timers, ActiveTimers, DpcCalls;
    PLIST_ENTRY ListHead, NextEntry;
    KIRQL OldIrql;
    PKTIMER Timer;
    PKDPC TimerDpc;
    ULONG Period;
    DPC_QUEUE_ENTRY DpcEntry[MAX_TIMER_DPCS];
    PKSPIN_LOCK_QUEUE LockQueue;
#ifdef CONFIG_SMP
    PKPRCB Prcb = KeGetCurrentPrcb();
#endif

    /* Disable interrupts */
    _disable();

    /* Query system and interrupt time */
    KeQuerySystemTime((PLARGE_INTEGER)&SystemTime);
    InterruptTime.QuadPart = KeQueryInterruptTime();
    Limit = KeTickCount.LowPart;

    /* Bring interrupts back */
    _enable();

    /* Get the index of the timer and normalize it */
    Index = PtrToLong(SystemArgument1);
    if ((Limit - Index) >= TIMER_TABLE_SIZE)
    {
        /* Normalize it */
        Limit = Index + TIMER_TABLE_SIZE - 1;
    }

    /* Setup index and actual limit */
    Index--;
    Limit &= (TIMER_TABLE_SIZE - 1);

    /* Setup accounting data */
    DpcCalls = 0;
    Timers = 24;
    ActiveTimers = 4;

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

    /* Start expiration loop */
    do
    {
        /* Get the current index */
        Index = (Index + 1) & (TIMER_TABLE_SIZE - 1);

        /* Get list pointers and loop the list */
        ListHead = &KiTimerTableListHead[Index].Entry;
        while (ListHead != ListHead->Flink)
        {
            /* Lock the timer and go to the next entry */
            LockQueue = KiAcquireTimerLock(Index);
            NextEntry = ListHead->Flink;

            /* Get the current timer and check its due time */
            Timers--;
            Timer = CONTAINING_RECORD(NextEntry, KTIMER, TimerListEntry);
            if ((NextEntry != ListHead) &&
                (Timer->DueTime.QuadPart <= InterruptTime.QuadPart))
            {
                /* It's expired, remove it */
                ActiveTimers--;
                KiRemoveEntryTimer(Timer);

                /* Make it non-inserted, unlock it, and signal it */
                Timer->Header.Inserted = FALSE;
                KiReleaseTimerLock(LockQueue);
                Timer->Header.SignalState = 1;

                /* Get the DPC and period */
                TimerDpc = Timer->Dpc;
                Period = Timer->Period;

                /* Check if there's any waiters */
                if (!IsListEmpty(&Timer->Header.WaitListHead))
                {
                    /* Check the type of event */
                    if (Timer->Header.Type == TimerNotificationObject)
                    {
                        /* Unwait the thread */
                        KxUnwaitThread(&Timer->Header, IO_NO_INCREMENT);
                    }
                    else
                    {
                        /* Otherwise unwait the thread and signal the timer */
                        KxUnwaitThreadForEvent((PKEVENT)Timer, IO_NO_INCREMENT);
                    }
                }

                /* Check if we have a period */
                if (Period)
                {
                    /* Calculate the interval and insert the timer */
                    Interval.QuadPart = Int32x32To64(Period, -10000);
                    while (!KiInsertTreeTimer(Timer, Interval));
                }

                /* Check if we have a DPC */
                if (TimerDpc)
                {
#ifdef CONFIG_SMP
                    /* 
                     * If the DPC is targeted to another processor,
                     * then insert it into that processor's DPC queue
                     * instead of delivering it now.
                     * If the DPC is a threaded DPC, and the current CPU
                     * has threaded DPCs enabled (KiExecuteDpc is actively parsing DPCs),
                     * then also insert it into the DPC queue for threaded delivery,
                     * instead of doing it here.
                     */
                    if (((TimerDpc->Number >= MAXIMUM_PROCESSORS) &&
                        ((TimerDpc->Number - MAXIMUM_PROCESSORS) != Prcb->Number)) ||
                        ((TimerDpc->Type == ThreadedDpcObject) && (Prcb->ThreadDpcEnable)))
                    {
                        /* Queue it */
                        KeInsertQueueDpc(TimerDpc,
                                         UlongToPtr(SystemTime.LowPart),
                                         UlongToPtr(SystemTime.HighPart));
                    }
                    else
#endif
                    {
                        /* Setup the DPC Entry */
                        DpcEntry[DpcCalls].Dpc = TimerDpc;
                        DpcEntry[DpcCalls].Routine = TimerDpc->DeferredRoutine;
                        DpcEntry[DpcCalls].Context = TimerDpc->DeferredContext;
                        DpcCalls++;
                        ASSERT(DpcCalls < MAX_TIMER_DPCS);
                    }
                }

                /* Check if we're done processing */
                if (!(ActiveTimers) || !(Timers))
                {
                    /* Release the dispatcher while doing DPCs */
                    KiReleaseDispatcherLock(DISPATCH_LEVEL);

                    /* Start looping all DPC Entries */
                    for (i = 0; DpcCalls; DpcCalls--, i++)
                    {
                        /* Call the DPC */
                        DpcEntry[i].Routine(DpcEntry[i].Dpc,
                                            DpcEntry[i].Context,
                                            UlongToPtr(SystemTime.LowPart),
                                            UlongToPtr(SystemTime.HighPart));
                    }

                    /* Reset accounting */
                    Timers = 24;
                    ActiveTimers = 4;

                    /* Lock the dispatcher database */
                    KiAcquireDispatcherLock();
                }
            }
            else
            {
                /* Check if the timer list is empty */
                if (NextEntry != ListHead)
                {
                    /* Sanity check */
                    ASSERT(KiTimerTableListHead[Index].Time.QuadPart <=
                           Timer->DueTime.QuadPart);

                    /* Update the time */
                    _disable();
                    KiTimerTableListHead[Index].Time.QuadPart =
                        Timer->DueTime.QuadPart;
                    _enable();
                }

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

                /* Check if we've scanned all the timers we could */
                if (!Timers)
                {
                    /* Release the dispatcher while doing DPCs */
                    KiReleaseDispatcherLock(DISPATCH_LEVEL);

                    /* Start looping all DPC Entries */
                    for (i = 0; DpcCalls; DpcCalls--, i++)
                    {
                        /* Call the DPC */
                        DpcEntry[i].Routine(DpcEntry[i].Dpc,
                                            DpcEntry[i].Context,
                                            UlongToPtr(SystemTime.LowPart),
                                            UlongToPtr(SystemTime.HighPart));
                    }

                    /* Reset accounting */
                    Timers = 24;
                    ActiveTimers = 4;

                    /* Lock the dispatcher database */
                    KiAcquireDispatcherLock();
                }

                /* Done looping */
                break;
            }
        }
    } while (Index != Limit);

    /* Verify the timer table, on debug builds */
    if (KeNumberProcessors == 1) KiCheckTimerTable(InterruptTime);

    /* Check if we still have DPC entries */
    if (DpcCalls)
    {
        /* Release the dispatcher while doing DPCs */
        KiReleaseDispatcherLock(DISPATCH_LEVEL);

        /* Start looping all DPC Entries */
        for (i = 0; DpcCalls; DpcCalls--, i++)
        {
            /* Call the DPC */
            DpcEntry[i].Routine(DpcEntry[i].Dpc,
                                DpcEntry[i].Context,
                                UlongToPtr(SystemTime.LowPart),
                                UlongToPtr(SystemTime.HighPart));
        }

        /* Lower IRQL if we need to */
        if (OldIrql != DISPATCH_LEVEL) KeLowerIrql(OldIrql);
    }
    else
    {
        /* Unlock the dispatcher */
        KiReleaseDispatcherLock(OldIrql);
    }
}
Example #4
0
VOID
NTAPI
KeSetSystemTime(IN PLARGE_INTEGER NewTime,
                OUT PLARGE_INTEGER OldTime,
                IN BOOLEAN FixInterruptTime,
                IN PLARGE_INTEGER HalTime OPTIONAL)
{
    TIME_FIELDS TimeFields;
    KIRQL OldIrql, OldIrql2;
    LARGE_INTEGER DeltaTime;
    PLIST_ENTRY ListHead, NextEntry;
    PKTIMER Timer;
    PKSPIN_LOCK_QUEUE LockQueue;
    LIST_ENTRY TempList, TempList2;
    ULONG Hand, i;

    /* Sanity checks */
    ASSERT((NewTime->HighPart & 0xF0000000) == 0);
    ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);

    /* Check if this is for the HAL */
    if (HalTime) RtlTimeToTimeFields(HalTime, &TimeFields);

    /* Set affinity to this CPU, lock the dispatcher, and raise IRQL */
    KeSetSystemAffinityThread(1);
    OldIrql = KiAcquireDispatcherLock();
    KeRaiseIrql(HIGH_LEVEL, &OldIrql2);

    /* Query the system time now */
    KeQuerySystemTime(OldTime);

    /* Set the new system time (ordering of these operations is critical) */
    SharedUserData->SystemTime.High2Time = NewTime->HighPart;
    SharedUserData->SystemTime.LowPart = NewTime->LowPart;
    SharedUserData->SystemTime.High1Time = NewTime->HighPart;

    /* Check if this was for the HAL and set the RTC time */
    if (HalTime) ExCmosClockIsSane = HalSetRealTimeClock(&TimeFields);

    /* Calculate the difference between the new and the old time */
    DeltaTime.QuadPart = NewTime->QuadPart - OldTime->QuadPart;

    /* Update system boot time */
    KeBootTime.QuadPart += DeltaTime.QuadPart;
    KeBootTimeBias = KeBootTimeBias + DeltaTime.QuadPart;

    /* Lower IRQL back */
    KeLowerIrql(OldIrql2);

    /* Check if we need to adjust interrupt time */
    if (FixInterruptTime) ASSERT(FALSE);

    /* Setup a temporary list of absolute timers */
    InitializeListHead(&TempList);

    /* Loop current timers */
    for (i = 0; i < TIMER_TABLE_SIZE; i++)
    {
        /* Loop the entries in this table and lock the timers */
        ListHead = &KiTimerTableListHead[i].Entry;
        LockQueue = KiAcquireTimerLock(i);
        NextEntry = ListHead->Flink;
        while (NextEntry != ListHead)
        {
            /* Get the timer */
            Timer = CONTAINING_RECORD(NextEntry, KTIMER, TimerListEntry);
            NextEntry = NextEntry->Flink;

            /* Is it absolute? */
            if (Timer->Header.Absolute)
            {
                /* Remove it from the timer list */
                KiRemoveEntryTimer(Timer);

                /* Insert it into our temporary list */
                InsertTailList(&TempList, &Timer->TimerListEntry);
            }
        }

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

    /* Setup a temporary list of expired timers */
    InitializeListHead(&TempList2);

    /* Loop absolute timers */
    while (TempList.Flink != &TempList)
    {
        /* Get the timer */
        Timer = CONTAINING_RECORD(TempList.Flink, KTIMER, TimerListEntry);
        RemoveEntryList(&Timer->TimerListEntry);

        /* Update the due time and handle */
        Timer->DueTime.QuadPart -= DeltaTime.QuadPart;
        Hand = KiComputeTimerTableIndex(Timer->DueTime.QuadPart);
        Timer->Header.Hand = (UCHAR)Hand;

        /* Lock the timer and re-insert it */
        LockQueue = KiAcquireTimerLock(Hand);
        if (KiInsertTimerTable(Timer, Hand))
        {
            /* Remove it from the timer list */
            KiRemoveEntryTimer(Timer);

            /* Insert it into our temporary list */
            InsertTailList(&TempList2, &Timer->TimerListEntry);
        }

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

    /* Process expired timers. This releases the dispatcher lock. */
    KiTimerListExpire(&TempList2, OldIrql);

    /* Revert affinity */
    KeRevertToUserAffinityThread();
}