Geoff Chappell - Software Analyst
The KTIMER is the kernel’s representation of a timer object. Like all dispatcher objects, timers can be waited on until they get signalled. As an elaboration that is not supported for all dispatcher objects, a timer’s usefulness comes not just from being waitable. It can also be configured so that signalling causes a Deferred Procedure Call (DPC) to be scheduled. For timers, signalling is done by the kernel on noticing that a specified time has been reached. This specified time can be absolute or relative, the former being a system time, the latter being a difference from the current interrupt time.
Kernel-mode code allocates space for a KTIMER and gets it ready for use by calling either KeInitializeTimer or the newer, more capable, KeInitializeTimerEx. Thereafter, conditions for the timer’s expiration can be specified through the progressively newer and more capable functions KeSetTimer, KeSetTimerEx and KeSetCoalescableTimer. These functions each reset the timer to be non-signalled.
The kernel itself exposes timer objects to the Object Manager. Code in both kernel mode and user mode can call NtCreateTimer or ZwCreateTimer, as appropriate, to get the kernel to create a KTIMER within an ETIMER, which is then made accessible through a handle. A timer that is created this way can have a name, such that another handle can be obtained, most usefully in another process, by calling NtOpenTimer or ZwOpenTimer. Of course, well-behaved user-mode code doesn’t call these native API functions directly but instead goes through such higher-level functions as CreateWaitableTimerEx and OpenWaitableTimer which are exported from KERNEL32.
In all versions, the KTIMER is 0x28 and 0x40 bytes in 32-bit and 64-bit Windows respectively.
Offset (x86) | Offset (x64) | Definition | Versions | Remarks |
---|---|---|---|---|
0x00 | 0x00 |
DISPATCHER_HEADER Header; |
all | |
0x10 | 0x18 |
ULARGE_INTEGER DueTime; |
all | |
0x18 | 0x20 |
LIST_ENTRY TimerListEntry; |
all | |
0x20 | 0x30 |
KDPC *Dpc; |
all | |
0x38 |
ULONG Processor; |
6.1 to 1903 | x86 in Header | |
USHORT Processor; |
2004 and higher | |||
0x3A |
USHORT TimerType; |
2004 and higher | ||
0x24 | 0x38 (late 5.2 to 6.0); 0x3C |
BOOLEAN Inserted; |
3.10 to 3.51 | moves to Header |
LONG Period; |
4.0 to 6.0 | |||
ULONG Period; |
6.1 and higher |
The DueTime is the interrupt time at which the timer is set to expire.
Of several expansions of functionality that Windows NT 4.0 brought to timers, automatically restarting the timer at repeating intervals required more storage in the KTIMER. Three bytes had been left undefined as a side-effect of alignment after the Inserted member. To find four bytes for saving the whole Period that could be given to the new KeSetTimerEx function, the Inserted member was moved into the DISPATCHER_HEADER, taking space from the Size.
Much of the new functionality in successive versions has been accommodated by finding space inside the Header. The DISPATCHER_HEADER is a complex structure that begins all kernel objects that can be waited on. The following tables simplify by disregarding the nested unions, extracting only the branches that apply to timers.
Offset | Definition | Versions | Remarks |
---|---|---|---|
0x00 |
SHORT Type; |
3.10 to 3.50 | |
UCHAR Type; |
3.51 and higher | ||
UCHAR TimerType; |
10.0 and higher | ||
0x01 |
UCHAR Spare; |
3.51 only | |
UCHAR Absolute; |
4.0 to 6.0 | becomes bit in TimerControlFlags | |
union { UCHAR TimerControlFlags; struct { /* bit fields, follow link */ }; }; |
6.1 and higher | ||
0x02 |
SHORT Size; |
3.10 to 3.50 | |
USHORT Size; |
3.51 only | ||
UCHAR Size; |
4.0 to early 5.2 | ||
UCHAR Hand; |
late 5.2 and higher | ||
0x03 |
UCHAR Inserted; |
4.0 to 6.0 | becomes bit in TimerMiscFlags |
union { UCHAR TimerMiscFlags; struct { /* bit fields, follow link */ }; }; |
6.1 and higher | ||
0x04 |
LONG SignalState; |
3.51 and higher | |
0x08 |
LIST_ENTRY WaitListHead; |
3.51 and higher |
As for all dispatchable objects, the low 7 bits of the Type—or all 8 bits in version 3.51—are from the KOBJECTS enumeration. For the KTIMER specifically, these bits are 0x08 (TimerNotificationObject) or 0x09 (TimerSynchronizationObject) according to whether NotificationTimer or SynchronizationTimer is given as the Type argument when initialising the timer through the KeInitializeTimerEx function.