Esempio n. 1
0
ULONGLONG
KeQueryInterruptTime (
    VOID
    )

/*++

Routine Description:

    This function returns the current interrupt time by determining when the
    time is stable and then returning its value.

Arguments:

    CurrentTime - Supplies a pointer to a variable that will receive the
        current system time.

Return Value:

    None.

--*/

{

    LARGE_INTEGER CurrentTime;

    KiQueryInterruptTime(&CurrentTime);
    return CurrentTime.QuadPart;
}
Esempio n. 2
0
PLARGE_INTEGER
FASTCALL
KiComputeWaitInterval (
    IN PLARGE_INTEGER OriginalTime,
    IN PLARGE_INTEGER DueTime,
    IN OUT PLARGE_INTEGER NewTime
    )

/*++

Routine Description:

    This function recomputes the wait interval after a thread has been
    awakened to deliver a kernel APC.

Arguments:

    OriginalTime - Supplies a pointer to the original timeout value.

    DueTime - Supplies a pointer to the previous due time.

    NewTime - Supplies a pointer to a variable that receives the
        recomputed wait interval.

Return Value:

    A pointer to the new time is returned as the function value.

--*/

{

    //
    // If the original wait time was absolute, then return the same
    // absolute time. Otherwise, reduce the wait time remaining before
    // the time delay expires.
    //

    if (OriginalTime->QuadPart >= 0) {
        return OriginalTime;

    } else {
        KiQueryInterruptTime(NewTime);
        NewTime->QuadPart -= DueTime->QuadPart;
        return NewTime;
    }
}
Esempio n. 3
0
NTSTATUS
NtQueryTimer (
    IN HANDLE TimerHandle,
    IN TIMER_INFORMATION_CLASS TimerInformationClass,
    OUT PVOID TimerInformation,
    IN ULONG TimerInformationLength,
    OUT PULONG ReturnLength OPTIONAL
    )

/*++

Routine Description:

    This function queries the state of an timer object and returns the
    requested information in the specified record structure.

Arguments:

    TimerHandle - Supplies a handle to an timer object.

    TimerInformationClass - Supplies the class of information being requested.

    TimerInformation - Supplies a pointer to a record that is to receive the
        requested information.

    TimerInformationLength - Supplies the length of the record that is to
        receive the requested information.

    ReturnLength - Supplies an optional pointer to a variable that is to
        receive the actual length of information that is returned.

Return Value:

    TBS

--*/

{

    PETIMER ExTimer;
    PKTIMER KeTimer;
    KPROCESSOR_MODE PreviousMode;
    BOOLEAN State;
    NTSTATUS Status;
    LARGE_INTEGER TimeToGo;

    //
    // Establish an exception handler, probe the output arguments, reference
    // the timer object, and return the specified information. If the probe
    // fails, then return the exception code as the service status. Otherwise
    // return the status value returned by the reference object by handle
    // routine.
    //

    try {

        //
        // Get previous processor mode and probe output arguments if necessary.
        //

        PreviousMode = KeGetPreviousMode();
        if (PreviousMode != KernelMode) {
            ProbeForWrite(TimerInformation,
                          sizeof(TIMER_BASIC_INFORMATION),
                          sizeof(ULONG));

            if (ARGUMENT_PRESENT(ReturnLength)) {
                ProbeForWriteUlong(ReturnLength);
            }
        }

        //
        // Check argument validity.
        //

        if (TimerInformationClass != TimerBasicInformation) {
            return STATUS_INVALID_INFO_CLASS;
        }

        if (TimerInformationLength != sizeof(TIMER_BASIC_INFORMATION)) {
            return STATUS_INFO_LENGTH_MISMATCH;
        }

        //
        // Reference timer object by handle.
        //

        Status = ObReferenceObjectByHandle(TimerHandle,
                                           TIMER_QUERY_STATE,
                                           ExTimerObjectType,
                                           PreviousMode,
                                           (PVOID *)&ExTimer,
                                           NULL);

        //
        // If the reference was successful, then read the current state,
        // compute the time remaining, dereference the timer object, fill in
        // the information structure, and return the length of the information
        // structure if specified. If the write of the time information or the
        // return length fails, then do not report an error. When the caller
        // accesses the information structure or the length, an violation will
        // occur.
        //

        if (NT_SUCCESS(Status)) {
            KeTimer = &ExTimer->KeTimer;
            State = KeReadStateTimer(KeTimer);
            KiQueryInterruptTime(&TimeToGo);
            TimeToGo.QuadPart = KeTimer->DueTime.QuadPart - TimeToGo.QuadPart;
            ObDereferenceObject(ExTimer);
            try {
                ((PTIMER_BASIC_INFORMATION)TimerInformation)->TimerState = State;
                ((PTIMER_BASIC_INFORMATION)TimerInformation)->RemainingTime = TimeToGo;
                if (ARGUMENT_PRESENT(ReturnLength)) {
                    *ReturnLength = sizeof(TIMER_BASIC_INFORMATION);
                }

            } except(ExSystemExceptionFilter()) {
            }
        }

    //
    // If an exception occurs during the probe of the current state address,
    // then always handle the exception and return the exception code as the
    // status value.
    //

    } except(ExSystemExceptionFilter()) {
        return GetExceptionCode();
    }

    //
    // Return service status.
    //

    return Status;
}
Esempio n. 4
0
VOID
KiTimerExpiration (
    IN PKDPC TimerDpc,
    IN PVOID DeferredContext,
    IN PVOID SystemArgument1,
    IN PVOID SystemArgument2
    )

/*++

Routine Description:

    This function is called when the clock interupt routine discovers that
    a timer has expired.

Arguments:

    TimerDpc - Supplies a pointer to a control object of type DPC.

    DeferredContext - Not used.

    SystemArgument1 - Supplies the starting timer table index value to
        use for the timer table scan.

    SystemArgument2 - Not used.

Return Value:

    None.

--*/

{
    ULARGE_INTEGER CurrentTime;
    LIST_ENTRY ExpiredListHead;
    LONG HandLimit;
    LONG Index;
    PLIST_ENTRY ListHead;
    PLIST_ENTRY NextEntry;
    KIRQL OldIrql;
    PKTIMER Timer;

    //
    // Acquire the dispatcher database lock and read the current interrupt
    // time to determine which timers have expired.
    //

    KiLockDispatcherDatabase(&OldIrql);
    KiQueryInterruptTime((PLARGE_INTEGER)&CurrentTime);

    //
    // If the timer table has not wrapped, then start with the specified
    // timer table index value, and scan for timer entries that have expired.
    // Otherwise, start with the first entry in the timer table and scan the
    // entire table for timer entries that have expired.
    //
    // N.B. This later condition exists when DPC processing is blocked for a
    //      period longer than one round trip throught the timer table.
    //

    HandLimit = (LONG)KiQueryLowTickCount();
    if (((ULONG)(HandLimit - PtrToLong(SystemArgument1))) >= TIMER_TABLE_SIZE) {
        Index = - 1;
        HandLimit = TIMER_TABLE_SIZE - 1;

    } else {
        Index = (PtrToLong(SystemArgument1) - 1) & (TIMER_TABLE_SIZE - 1);
        HandLimit &= (TIMER_TABLE_SIZE - 1);
    }

    InitializeListHead(&ExpiredListHead);
    do {
        Index = (Index + 1) & (TIMER_TABLE_SIZE - 1);
        ListHead = &KiTimerTableListHead[Index];
        NextEntry = ListHead->Flink;
        while (NextEntry != ListHead) {
            Timer = CONTAINING_RECORD(NextEntry, KTIMER, TimerListEntry);
            if (Timer->DueTime.QuadPart <= CurrentTime.QuadPart) {

                //
                // The next timer in the current timer list has expired.
                // Remove the entry from the timer list and insert the
                // timer in the expired list.
                //

                RemoveEntryList(&Timer->TimerListEntry);
                InsertTailList(&ExpiredListHead, &Timer->TimerListEntry);
                NextEntry = ListHead->Flink;

            } else {
                break;
            }
        }

    } while(Index != HandLimit);

#if DBG

    if ((PtrToUlong(SystemArgument2) == 0) && (KeNumberProcessors == 1)) {
        KiCheckTimerTable(CurrentTime);
    }

#endif

    //
    // Process the expired timer list.
    //
    // N.B. The following function returns with the dispatcher database
    //      unlocked.
    //

    KiTimerListExpire(&ExpiredListHead, OldIrql);
    return;
}
Esempio n. 5
0
LOGICAL
FASTCALL
KiInsertTreeTimer (
    IN PRKTIMER Timer,
    IN LARGE_INTEGER Interval
    )

/*++

Routine Description:

    This function inserts a timer object in the timer queue.

    N.B. This routine assumes that the dispatcher data lock has been acquired.

Arguments:

    Timer - Supplies a pointer to a dispatcher object of type timer.

    Interval - Supplies the absolute or relative time at which the time
        is to expire.

Return Value:

    If the timer is inserted in the timer tree, than a value of TRUE is
    returned. Otherwise, a value of FALSE is returned.

--*/

{

    LARGE_INTEGER CurrentTime;
    LARGE_INTEGER SystemTime;
    LARGE_INTEGER TimeDifference;

    //
    // Clear the signal state of timer if the timer period is zero and set
    // the inserted state to TRUE.
    //

    Timer->Header.Inserted = TRUE;
    Timer->Header.Absolute = FALSE;
    if (Timer->Period == 0) {
        Timer->Header.SignalState = FALSE;
    }

    //
    // If the specified interval is not a relative time (i.e., is an absolute
    // time), then convert it to relative time.
    //

    if (Interval.HighPart >= 0) {
        KiQuerySystemTime(&SystemTime);
        TimeDifference.QuadPart = SystemTime.QuadPart - Interval.QuadPart;

        //
        // If the resultant relative time is greater than or equal to zero,
        // then the timer has already expired.
        //

        if (TimeDifference.HighPart >= 0) {
            Timer->Header.SignalState = TRUE;
            Timer->Header.Inserted = FALSE;
            return FALSE;
        }

        Interval = TimeDifference;
        Timer->Header.Absolute = TRUE;
    }

    //
    // Get the current interrupt time, insert the timer in the timer table,
    // and return the inserted state.
    //

    KiQueryInterruptTime(&CurrentTime);
    return KiInsertTimerTable(Interval, CurrentTime, Timer);
}
Esempio n. 6
0
LOGICAL
FASTCALL
KiInsertTimerTable (
    LARGE_INTEGER Interval,
    LARGE_INTEGER CurrentTime,
    IN PRKTIMER Timer
    )

/*++

Routine Description:

    This function inserts a timer object in the timer table.

    N.B. This routine assumes that the dispatcher data lock has been acquired.

Arguments:

    Interval - Supplies the relative timer before the timer is to expire.

    CurrentTime - supplies the current interrupt time.

    Timer - Supplies a pointer to a dispatcher object of type timer.

Return Value:

    If the timer is inserted in the timer tree, than a value of TRUE is
    returned. Otherwise, a value of FALSE is returned.

--*/

{

    ULONG Index;
    PLIST_ENTRY ListHead;
    PLIST_ENTRY NextEntry;
    PRKTIMER NextTimer;
    ULONG SearchCount;

    //
    // Compute the timer table index and set the timer expiration time.
    //

    Index = KiComputeTimerTableIndex(Interval, CurrentTime, Timer);

    //
    // If the timer is due before the first entry in the computed list
    // or the computed list is empty, then insert the timer at the front
    // of the list and check if the timer has already expired. Otherwise,
    // insert then timer in the sorted order of the list searching from
    // the back of the list forward.
    //
    // N.B. The sequence of operations below is critical to avoid the race
    //      condition that exists between this code and the clock interrupt
    //      code that examines the timer table lists to detemine when timers
    //      expire.
    //

    ListHead = &KiTimerTableListHead[Index];
    NextEntry = ListHead->Blink;

#if DBG

    SearchCount = 0;

#endif

    while (NextEntry != ListHead) {

        //
        // Compute the maximum search count.
        //

#if DBG

        SearchCount += 1;
        if (SearchCount > KiMaximumSearchCount) {
            KiMaximumSearchCount = SearchCount;
        }

#endif

        NextTimer = CONTAINING_RECORD(NextEntry, KTIMER, TimerListEntry);
        if (((Timer->DueTime.HighPart == NextTimer->DueTime.HighPart) &&
            (Timer->DueTime.LowPart >= NextTimer->DueTime.LowPart)) ||
            (Timer->DueTime.HighPart > NextTimer->DueTime.HighPart)) {
            InsertHeadList(NextEntry, &Timer->TimerListEntry);
            return TRUE;
        }

        NextEntry = NextEntry->Blink;
    }

    //
    // The computed list is empty or the timer is due to expire before
    // the first entry in the list. Insert the entry in the computed
    // timer table list, then check if the timer has expired.
    //
    // Note that it is critical that the interrupt time not be captured
    // until after the timer has been completely inserted into the list.
    //
    // Otherwise, the clock interrupt code can think the list is empty,
    // and the code here that checks if the timer has expired will use
    // a stale interrupt time.
    //

    InsertHeadList(ListHead, &Timer->TimerListEntry);
    KiQueryInterruptTime(&CurrentTime);
    if (((Timer->DueTime.HighPart == (ULONG)CurrentTime.HighPart) &&
        (Timer->DueTime.LowPart <= CurrentTime.LowPart)) ||
        (Timer->DueTime.HighPart < (ULONG)CurrentTime.HighPart)) {

        //
        // The timer is due to expire before the current time. Remove the
        // timer from the computed list, set its status to Signaled, set
        // its inserted state to FALSE, and
        //

        KiRemoveTreeTimer(Timer);
        Timer->Header.SignalState = TRUE;
    }

    return Timer->Header.Inserted;
}
Esempio n. 7
0
LOGICAL
FASTCALL
KiReinsertTreeTimer (
    IN PRKTIMER Timer,
    IN ULARGE_INTEGER DueTime
    )

/*++

Routine Description:

    This function reinserts a timer object in the timer queue.

    N.B. This routine assumes that the dispatcher data lock has been acquired.

Arguments:

    Timer - Supplies a pointer to a dispatcher object of type timer.

    DueTime - Supplies the absolute time the timer is to expire.

Return Value:

    If the timer is inserted in the timer tree, than a value of TRUE is
    returned. Otherwise, a value of FALSE is returned.

--*/

{

    LARGE_INTEGER CurrentTime;
    LARGE_INTEGER Interval;

    //
    // Clear the signal state of timer if the timer period is zero and set
    // the inserted state to TRUE.
    //

    Timer->Header.Inserted = TRUE;
    if (Timer->Period == 0) {
        Timer->Header.SignalState = FALSE;
    }

    //
    // Compute the interval between the current time and the due time.
    // If the resultant relative time is greater than or equal to zero,
    // then the timer has already expired.
    //

    KiQueryInterruptTime(&CurrentTime);
    Interval.QuadPart = CurrentTime.QuadPart - DueTime.QuadPart;
    if (Interval.QuadPart >= 0) {
        Timer->Header.SignalState = TRUE;
        Timer->Header.Inserted = FALSE;
        return FALSE;
    }

    //
    // Insert the timer in the timer table and return the inserted state.
    //

    return KiInsertTimerTable(Interval, CurrentTime, Timer);
}