Windows System Software -- Consulting, Training, Development -- Unique Expertise, Guaranteed Results

Home NTDEV
Before Posting...
Please check out the Community Guidelines in the Announcements and Administration Category.

Why is KTIMER useful?

0xrepnz0xrepnz Member Posts: 16
edited January 18 in NTDEV

Hey,
I have this exercise where I have PASSIVE_LEVEL job I need to perform every 10 seconds.
I can use KTIMER, But then (as far as I know) the routine will run at DISPATCH_LEVEL so I'll have to use a work item to queue the job..
I found it was easier to just create a system thread then use KeWaitForSingleObject like this:

typedef VOID (*PERIODIC_ROUTINE)(PVOID Context);

typedef struct _PERIODIC_JOB {
    PERIODIC_ROUTINE Routine;
    PVOID Context;
    KEVENT ExitEvent;
    LARGE_INTEGER Interval;
    HANDLE SystemThreadHandle;
} PERIODIC_JOB;


static
VOID
PeriodicSystemThread(
    __in PVOID Context
)
{
    NTSTATUS Status;
    PERIODIC_JOB* Job = (PERIODIC_JOB*)Context;


    while (TRUE) {

        Status = KeWaitForSingleObject(
            &Job->ExitEvent,
            Executive,
            KernelMode,
            FALSE,
            &Job->Interval
        );


        if (Status == STATUS_SUCCESS) {
            //
            // The thread was signaled to exit.
            //
            PsTerminateSystemThread(STATUS_SUCCESS);
        }

        if (Status == STATUS_TIMEOUT) {
            Job->Routine(Job->Context);
            continue;
        }

        KeBugCheck(0x1337);
    }
}

NTSTATUS
CreatePeriodicJob(
    __out PERIODIC_JOB* Job,
    __in PERIODIC_ROUTINE Routine,
    __in PLARGE_INTEGER Interval,
    __in_opt PVOID Context
    )
{
    NTSTATUS Status;
    OBJECT_ATTRIBUTES ThreadAttributes;

    RtlZeroMemory(Job, sizeof(PERIODIC_JOB));

    Job->Context = Context;
    Job->Routine = Routine;
    Job->Interval.QuadPart = Interval->QuadPart;

    KeInitializeEvent(&Job->ExitEvent, NotificationEvent, FALSE);

    InitializeObjectAttributes(&ThreadAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);

    return PsCreateSystemThread(
        &Job->SystemThreadHandle,
        0,
        &ThreadAttributes,
        NULL,
        NULL,
        PeriodicSystemThread,
        Job
    );
}

NTSTATUS
StopPeriodicJob(
    __in PERIODIC_JOB* Job,
    __in PLARGE_INTEGER Timeout
    )
{
    KeSetEvent(&Job->ExitEvent, IO_NO_INCREMENT, FALSE);
    return ZwWaitForSingleObject(Job->SystemThreadHandle, FALSE, Timeout);
}

My question is:
1) What is the general use case of KTIMER? In which case it's useful?
2) Is it bad to use a system thread like I did?

I guess that in my case it does not really matter but in case the timer is not a periodic timer it's better to use KeSetTimer to save the overhead
of creating threads..

Sorry in advance if I'm missing something.

Thank you :smiley:

Comments

  • Peter_Viscarola_(OSR)Peter_Viscarola_(OSR) Administrator Posts: 7,683

    You use timers whenever you want a callback at IRQL DISPATCH_LEVEL that occurs after some amount of time has elapsed. Any time you’re waiting for something to happen that has a max time that it should take.

    If you want to do something (a) periodically, (b) you need to do that at IRQL PASSIVE_LEVEL, and you’re willing to accept the overhead of the scheduling operations (inherent in doing the work at IRQ PASSIVE_LEVEL in any case), it’s probably worth spinning up a system thread as you have done.

    Otherwise, KTIMER is your friend.

    Peter

    Peter Viscarola
    OSR
    @OSRDrivers

  • 0xrepnz0xrepnz Member Posts: 16
    edited January 18
    Thank you for your answer!

    >Any time you’re waiting for something to happen that has a max time that it should take.

    If I understand correctly, In this case I can still use KEVENT and call KeWaitForSingleObject to wait for this max time, then signal the event when the job is done. The only advantage I can think of is the fact that I don't need to block any thread while waiting for the callback

    Can you give me one real scenario where KTIMER would be useful?
  • Peter_Viscarola_(OSR)Peter_Viscarola_(OSR) Administrator Posts: 7,683

    In this case I can still use KEVENT and call KeWaitForSingleObject to wait for this max time

    Hmmm... in what context? Still in your system thread, perhaps. Otherwise, you don’t want to block an arbitrary thread, right?

    Can you give me one real scenario where KTIMER would be useful?

    It’s very device dependent, of course. How about for a deadman timer on a decide? You start a request on the device, and it’s supposed to finish in less than 250ms and if it doesn’t, you need to reset the the device and retry the request... so, you set the timer to manage the timeout.

    Or during device initialization: You start the device initializing and then you need to wait for some time before the device is ready to process requests. Again, you set use a timer here.

    Really, the KTIMER is your go to facility for managing timeouts. It’s less common to want to spin a thread for this and run the timeout at PASSIVE_LEVEL.

    Peter

    Peter Viscarola
    OSR
    @OSRDrivers

  • 0xrepnz0xrepnz Member Posts: 16

    Ok, thanks!

Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Upcoming OSR Seminars
OSR has suspended in-person seminars due to the Covid-19 outbreak. But, don't miss your training! Attend via the internet instead!
Kernel Debugging 30 Mar 2020 OSR Seminar Space
Developing Minifilters 20 Apr 2020 LIVE ONLINE
Writing WDF Drivers 11 May 2020 LIVE ONLINE
Internals & Software Drivers 28 Sept 2020 Dulles, VA