Why is KTIMER useful?

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:

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

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?

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

Ok, thanks!