!timer Abnormalities


The kernel debugger extension command !timer displays information about all outstanding timers in the system. This document explains some of the abnormalities in the output of this command.

Far out expiration times

Some timers in the system have expiration times (i.e. time when the timer will fire) set very far out in the future.
kd> !timer
Dump system timers

Interrupt time: 02e93b10 00000013 [10/22/2008 22:46:48.740]

List Timer    Interrupt Low/High     Fire Time              DPC/thread
. . .
464 831d7378   e36e417f 7e36cb37 [ 9/13/30828 18:48:05.477]  thread 831d72f0
Timeout specified to NtWaitForSingleObject() is in 100nS intervals and is expressed as a -ve number to denote relative time.
NTSTATUS
NtWaitForSingleObject(
    IN HANDLE  Handle,
    IN BOOLEAN  Alertable,
    IN PLARGE_INTEGER  Timeout OPTIONAL );
When the caller of this API specifies the Timeout value as 0x7fffffff'ffffffff, which is the largest +ve 64-bit signed integer, it translates to the time 9/13/30828 18:48:05.477. The mswsock.dll function SockWaitForSingleObject() uses this number to imply an INFINITE timeout. This is functionally still correct as the timer never expires as it is intended to.

Following is the assembler code snippet that calls NtWaitForSingleObject().
mswsock!SockWaitForSingleObject+0x12c:
75232220 83cfff          or      edi,0FFFFFFFFh
75232223 beffffff7f      mov     esi,7FFFFFFFh
. 
.
.
75232232 897de8          mov     dword ptr [ebp-18h],edi
75232235 8975ec          mov     dword ptr [ebp-14h],esi
.
.
.
75232274 8d45e8          lea     eax,[ebp-18h] <<< Timeout
75232277 50              push    eax
75232278 6a01            push    1
7523227a ff7508          push    dword ptr [ebp+8]
7523227d ff15d8102375    call    dword ptr [mswsock!_imp__NtWaitForSingleObject (752310d8)]

Timers set to "NEVER" expire

Some timers in the system have expiration times set to never expire, so why would someone use a timer that will never expire?

Here is an example of 2 such timers that have threads waiting on them.
kd> !timer
Dump system timers

Interrupt time: 02e93b10 00000013 [10/22/2008 22:46:48.740]

List Timer    Interrupt Low/High     Fire Time              DPC/thread
. . .
13 846d8ce8   cc154910 80000002 [         NEVER         ]  thread 846d8c60
. . .
   830d0658   7a122690 80000001 [         NEVER         ]  thread 830d05d0

kd> !thread 846d8c60 
THREAD 846d8c60  Cid 0424.044c  Teb: 7ffde000 Win32Thread: 00000000 WAIT: (DelayExecution) UserMode Alertable
    846d8ce8  NotificationTimer

kd> !thread 830d05d0  
THREAD 830d05d0  Cid 054c.0994  Teb: 7ffaf000 Win32Thread: 00000000 WAIT: (DelayExecution) UserMode Alertable
    830d0658  NotificationTimer

Here is the call stack for such a thread
kd> k
ChildEBP RetAddr  
98b2cc68 818b0943 nt!KiSwapContext+0x26
98b2ccac 818af6ee nt!KiSwapThread+0x433
98b2cd08 81a0dff3 nt!KeDelayExecutionThread+0x472
98b2cd54 8189c9aa nt!NtDelayExecution+0x8d
98b2cd54 773e9a94 nt!KiFastCallEntry+0x12a
0283fae4 773e83b4 ntdll!KiFastSystemCallRet
0283fae8 7755c350 ntdll!NtDelayExecution+0xc
0283fb50 6d48da2f kernel32!SleepEx+0x62
Both these threads are waiting in an alertable wait initiated from user mode with the call to SleepEx(). The caller invokes SleepEx() with a timeout of -1 (INFINITE) since the thread actually wants to wait for a user mode APC delivery wihtout for any specific time out interval.

As seen in the code below SleepEx() is special cased for the timeout value of (-1) for which it actually sets up a timer with the maximum possible relative timeout i.e. 0x80000000`00000000. This is why the time shows up as "NEVER".
kernel32!SleepEx+0x24 :
7755c322 33ff            xor     edi,edi
. . . 

77520168 897ddc          mov     dword ptr [ebp-24h],edi
7752016b c745e000000080  mov     dword ptr [ebp-20h],80000000h
77520172 8d75dc          lea     esi,[ebp-24h]
. . . 
7755c346 56              push    esi ; Delay Interval 
7755c347 ff750c          push    dword ptr [ebp+0Ch]
7755c34a ff15a8155177    call    dword ptr [kernel32!_imp__NtDelayExecution (775115a8)]
NTSTATUS
NtDelayExecution(
  IN BOOLEAN              Alertable,
  IN PLARGE_INTEGER       DelayInterval );