Example #1
0
NTSTATUS
NtSetTimer (
    IN HANDLE TimerHandle,
    IN PLARGE_INTEGER DueTime,
    IN PTIMER_APC_ROUTINE TimerApcRoutine OPTIONAL,
    IN PVOID TimerContext OPTIONAL,
    IN BOOLEAN WakeTimer,
    IN LONG Period OPTIONAL,
    OUT PBOOLEAN PreviousState OPTIONAL
    )

/*++

Routine Description:

    This function sets an timer object to a Not-Signaled state and sets the timer
    to expire at the specified time.

Arguments:

    TimerHandle - Supplies a handle to an timer object.

    DueTime - Supplies a pointer to absolute of relative time at which the
        timer is to expire.

    TimerApcRoutine - Supplies an optional pointer to a function which is to
        be executed when the timer expires. If this parameter is not specified,
        then the TimerContext parameter is ignored.

    TimerContext - Supplies an optional pointer to an arbitrary data structure
        that will be passed to the function specified by the TimerApcRoutine
        parameter. This parameter is ignored if the TimerApcRoutine parameter
        is not specified.

    WakeTimer - Supplies a boolean value that specifies whether the timer
        wakes computer operation if sleeping

    Period - Supplies an optional repetitive period for the timer.

    PreviousState - Supplies an optional pointer to a variable that will
        receive the previous state of the timer object.

Return Value:

    TBS

--*/

{

    BOOLEAN AssociatedApc;
    BOOLEAN Dereference;
    PETHREAD ExThread;
    PETIMER ExTimer;
    LARGE_INTEGER ExpirationTime;
    KIRQL OldIrql1;
    KPROCESSOR_MODE PreviousMode;
    BOOLEAN State;
    NTSTATUS Status;

    //
    // Establish an exception handler, probe the due time and previous state
    // address if specified, reference the timer object, and set the timer
    // object. 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 previous state address
        // if necessary.
        //

        PreviousMode = KeGetPreviousMode();
        if (PreviousMode != KernelMode) {
            if (ARGUMENT_PRESENT(PreviousState)) {
                ProbeForWriteBoolean(PreviousState);
            }

            ProbeForRead(DueTime, sizeof(LARGE_INTEGER), sizeof(ULONG));
        }

        //
        // Check argument validity.
        //

        if (Period < 0) {
            return STATUS_INVALID_PARAMETER_6;
        }

        //
        // Capture the expiration time.
        //

        ExpirationTime = *DueTime;

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

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

        //
        // If this WakeTimer flag is set, return the appropiate informational
        // success status code.
        //

        if (NT_SUCCESS(Status) && WakeTimer && !PoWakeTimerSupported()) {
            Status = STATUS_TIMER_RESUME_IGNORED;
        }

        //
        // If the reference was successful, then cancel the timer object, set
        // the timer object, dereference time object, and write the previous
        // state value if specified. If the write of the previous state value
        // fails, then do not report an error. When the caller attempts to
        // access the previous state value, an access violation will occur.
        //

        if (NT_SUCCESS(Status)) {
            ExAcquireSpinLock(&ExTimer->Lock, &OldIrql1);

            if (ExTimer->ApcAssociated) {
                ExThread = CONTAINING_RECORD(ExTimer->TimerApc.Thread, ETHREAD, Tcb);
                ExAcquireSpinLockAtDpcLevel(&ExThread->ActiveTimerListLock);
                RemoveEntryList(&ExTimer->ActiveTimerListEntry);
                ExTimer->ApcAssociated = FALSE;
                ExReleaseSpinLockFromDpcLevel(&ExThread->ActiveTimerListLock);
                KeCancelTimer(&ExTimer->KeTimer);
                KeRemoveQueueDpc(&ExTimer->TimerDpc);
                KeRemoveQueueApc(&ExTimer->TimerApc);
                Dereference = TRUE;

            } else {
                KeCancelTimer(&ExTimer->KeTimer);
                Dereference = FALSE;
            }

            //
            // Read the current state of the timer.
            //

            State = KeReadStateTimer(&ExTimer->KeTimer);

            //
            // If this is a wake timer ensure it's on the wake timer list
            //

            ExTimer->WakeTimer = WakeTimer;
            ExAcquireSpinLockAtDpcLevel(&ExpWakeTimerListLock);
            if (WakeTimer) {
                if (!ExTimer->WakeTimerListEntry.Flink) {
                    InsertTailList(&ExpWakeTimerList, &ExTimer->WakeTimerListEntry);
                }
            } else {
                if (ExTimer->WakeTimerListEntry.Flink) {
                    RemoveEntryList(&ExTimer->WakeTimerListEntry);
                    ExTimer->WakeTimerListEntry.Flink = NULL;
                }
            }
            ExReleaseSpinLockFromDpcLevel(&ExpWakeTimerListLock);

            //
            // If an APC routine is specified, then initialize the APC, acquire the
            // thread's active time list lock, insert the timer in the thread's
            // active timer list, set the timer with an associated DPC, and set the
            // associated APC flag TRUE. Otherwise set the timer without an associated
            // DPC, and set the associated APC flag FALSE.
            //

            ExTimer->Period = Period;
            if (ARGUMENT_PRESENT(TimerApcRoutine)) {
                ExThread = PsGetCurrentThread();
                KeInitializeApc(&ExTimer->TimerApc,
                                &ExThread->Tcb,
                                CurrentApcEnvironment,
                                ExpTimerApcRoutine,
                                (PKRUNDOWN_ROUTINE)NULL,
                                (PKNORMAL_ROUTINE)TimerApcRoutine,
                                PreviousMode,
                                TimerContext);

                ExAcquireSpinLockAtDpcLevel(&ExThread->ActiveTimerListLock);
                InsertTailList(&ExThread->ActiveTimerListHead,
                               &ExTimer->ActiveTimerListEntry);

                ExTimer->ApcAssociated = TRUE;
                ExReleaseSpinLockFromDpcLevel(&ExThread->ActiveTimerListLock);
                KeSetTimerEx(&ExTimer->KeTimer,
                             ExpirationTime,
                             Period,
                             &ExTimer->TimerDpc);

                AssociatedApc = TRUE;

            } else {
                KeSetTimerEx(&ExTimer->KeTimer,
                             ExpirationTime,
                             Period,
                             NULL);

                AssociatedApc = FALSE;
            }

            ExReleaseSpinLock(&ExTimer->Lock, OldIrql1);

            //
            // Dereference the object as appropriate.
            //

            if (Dereference) {
                ObDereferenceObject((PVOID)ExTimer);
            }

            if (AssociatedApc == FALSE) {
                ObDereferenceObject((PVOID)ExTimer);
            }

            if (ARGUMENT_PRESENT(PreviousState)) {
                try {
                    *PreviousState = State;

                } 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;
}
Example #2
0
VOID
ExTimerRundown (
    )

/*++

Routine Description:

    This function is called when a thread is about to be terminated to
    process the active timer list. It is assumed that APC's have been
    disabled for the subject thread, thus this code cannot be interrupted
    to execute an APC for the current thread.

Arguments:

    None.

Return Value:

    None.

--*/

{

    BOOLEAN Dereference;
    PETHREAD ExThread;
    PETIMER ExTimer;
    PLIST_ENTRY NextEntry;
    KIRQL OldIrql1;

    //
    // Process each entry in the active timer list.
    //

    ExThread = PsGetCurrentThread();
    ExAcquireSpinLock(&ExThread->ActiveTimerListLock, &OldIrql1);
    NextEntry = ExThread->ActiveTimerListHead.Flink;
    while (NextEntry != &ExThread->ActiveTimerListHead) {
        ExTimer = CONTAINING_RECORD(NextEntry, ETIMER, ActiveTimerListEntry);

        //
        // Increment the reference count on the object so that it cannot be
        // deleted, and then drop the active timer list lock.
        //
        // N. B. The object reference cannot fail and will acquire no mutexes.
        //

        ObReferenceObject(ExTimer);
        ExReleaseSpinLock(&ExThread->ActiveTimerListLock, OldIrql1);

        //
        // Acquire the timer spin lock and reacquire the active time list spin
        // lock. If the timer is still in the current thread's active timer
        // list, then cancel the timer, remove the timer's DPC from the DPC
        // queue, remove the timer's APC from the APC queue, remove the timer
        // from the thread's active timer list, and set the associate APC
        // flag FALSE.
        //
        // N. B. The spin locks for the timer and the active timer list must be
        //  acquired in the order: 1) timer lock, 2) thread list lock.
        //

        ExAcquireSpinLock(&ExTimer->Lock, &OldIrql1);
        ExAcquireSpinLockAtDpcLevel(&ExThread->ActiveTimerListLock);
        if ((ExTimer->ApcAssociated) && (&ExThread->Tcb == ExTimer->TimerApc.Thread)) {
            RemoveEntryList(&ExTimer->ActiveTimerListEntry);
            ExTimer->ApcAssociated = FALSE;
            KeCancelTimer(&ExTimer->KeTimer);
            KeRemoveQueueDpc(&ExTimer->TimerDpc);
            KeRemoveQueueApc(&ExTimer->TimerApc);
            Dereference = TRUE;

        } else {
            Dereference = FALSE;
        }

        ExReleaseSpinLockFromDpcLevel(&ExThread->ActiveTimerListLock);
        ExReleaseSpinLock(&ExTimer->Lock, OldIrql1);
        if (Dereference) {
            ObDereferenceObject((PVOID)ExTimer);
        }

        ObDereferenceObject((PVOID)ExTimer);

        //
        // Raise IRQL to DISPATCH_LEVEL and reacquire active timer list
        // spin lock.
        //

        ExAcquireSpinLock(&ExThread->ActiveTimerListLock, &OldIrql1);
        NextEntry = ExThread->ActiveTimerListHead.Flink;
    }

    ExReleaseSpinLock(&ExThread->ActiveTimerListLock, OldIrql1);
    return;
}
Example #3
0
NTSTATUS
NtCancelTimer (
    IN HANDLE TimerHandle,
    OUT PBOOLEAN CurrentState OPTIONAL
    )

/*++

Routine Description:

    This function cancels a timer object.

Arguments:

    TimerHandle - Supplies a handle to an timer object.

    CurrentState - Supplies an optional pointer to a variable that will
        receive the current state of the timer object.

Return Value:

    TBS

--*/

{

    BOOLEAN Dereference;
    PETHREAD ExThread;
    PETIMER ExTimer;
    KIRQL OldIrql1;
    KPROCESSOR_MODE PreviousMode;
    BOOLEAN State;
    NTSTATUS Status;

    //
    // Establish an exception handler, probe the current state address if
    // specified, reference the timer object, and cancel the timer object.
    // 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 current state address if
        // necessary.
        //

        PreviousMode = KeGetPreviousMode();
        if ((PreviousMode != KernelMode) && (ARGUMENT_PRESENT(CurrentState))) {
            ProbeForWriteBoolean(CurrentState);
        }

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

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

        //
        // If the reference was successful, then cancel the timer object,
        // dereference the timer object, and write the current state value
        // if specified. If the write attempt fails, then do not report an
        // error. When the caller attempts to access the current state value,
        // an access violation will occur.
        //

        if (NT_SUCCESS(Status)) {
            ExAcquireSpinLock(&ExTimer->Lock, &OldIrql1);
            if (ExTimer->ApcAssociated) {
                ExThread = CONTAINING_RECORD(ExTimer->TimerApc.Thread, ETHREAD, Tcb);
                ExAcquireSpinLockAtDpcLevel(&ExThread->ActiveTimerListLock);
                RemoveEntryList(&ExTimer->ActiveTimerListEntry);
                ExTimer->ApcAssociated = FALSE;
                ExReleaseSpinLockFromDpcLevel(&ExThread->ActiveTimerListLock);
                KeCancelTimer(&ExTimer->KeTimer);
                KeRemoveQueueDpc(&ExTimer->TimerDpc);
                KeRemoveQueueApc(&ExTimer->TimerApc);
                Dereference = TRUE;

            } else {
                KeCancelTimer(&ExTimer->KeTimer);
                Dereference = FALSE;
            }

            if (ExTimer->WakeTimerListEntry.Flink) {
                ExAcquireSpinLockAtDpcLevel(&ExpWakeTimerListLock);

                //
                // Check again as ExGetNextWakeTime might have removed it.
                //
                if (ExTimer->WakeTimerListEntry.Flink) {
                    RemoveEntryList(&ExTimer->WakeTimerListEntry);
                    ExTimer->WakeTimerListEntry.Flink = NULL;
                }
                ExReleaseSpinLockFromDpcLevel(&ExpWakeTimerListLock);
            }

            ExReleaseSpinLock(&ExTimer->Lock, OldIrql1);
            if (Dereference) {
                ObDereferenceObject((PVOID)ExTimer);
            }

            //
            // Read current state of timer, dereference timer object, and set
            // current state.
            //

            State = KeReadStateTimer(&ExTimer->KeTimer);
            ObDereferenceObject(ExTimer);
            if (ARGUMENT_PRESENT(CurrentState)) {
                try {
                    *CurrentState = State;

                } 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;
}
Example #4
0
VOID
NTAPI
ExTimerRundown(VOID)
{
    PETHREAD Thread = PsGetCurrentThread();
    KIRQL OldIrql;
    PLIST_ENTRY CurrentEntry;
    PETIMER Timer;
    ULONG DerefsToDo;

    /* Lock the Thread's Active Timer List and loop it */
    KeAcquireSpinLock(&Thread->ActiveTimerListLock, &OldIrql);
    CurrentEntry = Thread->ActiveTimerListHead.Flink;
    while (CurrentEntry != &Thread->ActiveTimerListHead)
    {
        /* Get the timer */
        Timer = CONTAINING_RECORD(CurrentEntry, ETIMER, ActiveTimerListEntry);

        /* Reference it */
        ObReferenceObject(Timer);
        DerefsToDo = 1;

        /* Unlock the list */
        KeReleaseSpinLock(&Thread->ActiveTimerListLock, OldIrql);

        /* Lock the Timer */
        KeAcquireSpinLock(&Timer->Lock, &OldIrql);

        /* Lock the list again */
        KeAcquireSpinLockAtDpcLevel(&Thread->ActiveTimerListLock);

        /* Make sure that the timer is valid */
        if ((Timer->ApcAssociated) && (&Thread->Tcb == Timer->TimerApc.Thread))
        {
            /* Remove it from the list */
            RemoveEntryList(&Timer->ActiveTimerListEntry);
            Timer->ApcAssociated = FALSE;

            /* Cancel the timer and remove its DPC and APC */
            KeCancelTimer(&Timer->KeTimer);
            KeRemoveQueueDpc(&Timer->TimerDpc);
            if (KeRemoveQueueApc(&Timer->TimerApc)) DerefsToDo++;

            /* Add another dereference to do */
            DerefsToDo++;
        }

        /* Unlock the list */
        KeReleaseSpinLockFromDpcLevel(&Thread->ActiveTimerListLock);

        /* Unlock the Timer */
        KeReleaseSpinLock(&Timer->Lock, OldIrql);

        /* Dereference it */
        ObDereferenceObjectEx(Timer, DerefsToDo);

        /* Loop again */
        KeAcquireSpinLock(&Thread->ActiveTimerListLock, &OldIrql);
        CurrentEntry = Thread->ActiveTimerListHead.Flink;
    }

    /* Release lock and return */
    KeReleaseSpinLock(&Thread->ActiveTimerListLock, OldIrql);
}