Freigeben über


A NULL and zero wait timeout are not the same

When you call KeWaitForSingleObject or KeWaitForMultipleObjects you can provide a pointer to a timeout value. What value you pass for the pointer value makes a huge difference. This subtle distinction is something that first time driver writers do not grasp and get wrong.

If you want to infinitely wait, you pass NULL for the timeout. You must be at IRQL == PASSIVE_LEVEL to infinitely wait.

If you want to perform a test and exit (e.g. do not wait all, just try to acquire the handle and return immediately), you pass a pointer which points to 0x0. You can be at IRQL <= DISPATCH_LEVEL if you want to perform the tes and exit. This allows you to optimize a code path at DISPATCH_LEVEL and then queue to PASSIVE_LEVEL on in the case where you cannot acquire the handle.

Here is a summary of the different waits (excluding absolute):

Behavior Code
Infinitely wait
 KeWaitForSingleObject( <dispatcher object> ,                      Executive,                      KernelMode,                      FALSE,                      NULL);
Test and exit
 LARGE_INTEGER timeout;timeout.QuadPart = 0x0;KeWaitForSingleObject( <dispatcher object> ,                      Executive,                      KernelMode,                      FALSE,                      &timeout);
Relative timeout of 500 ms
 LARGE_INTEGER timeout;timeout.QuadPart = -5 * 10   // 100 ns to 1 us                      * 1000 // us to ms                      * 100; // 1ms to 100 msKeWaitForSingleObject( <dispatcher object> ,                      Executive,                      KernelMode,                      FALSE,                      &timeout);

Comments

  • Anonymous
    August 25, 2006
    The best part about this is that it's handled inconsistently in other areas; e.g. NDIS uses zero for an infinite wait (but then again, it's not a pointer arg.)
  • Anonymous
    August 25, 2006
    Timeouts are measured in 100 ns intervals so the last example be -500100010 == 500 ms.
  • Anonymous
    August 28, 2006
    Pavel, that's what I get for copying from a bad code sample ;).  The post has been fixed.  Of course, what i should have used is WDF_REL_TIMEOUT_IN_MS() and not even bothered with the math.

    Steve, that's the thing with the NDIS wait (NdisWaitEvent) ...no pointer argument for the time.  It is more like the UM WaitForSingleObject in that the time is just an integral value...unfortunately, it makes matters worse because an infinite wait in UM is INFINITE (-1), while the NDIS KM infinite wait is zero.  <sigh>.

    d
  • Anonymous
    August 28, 2006
    and don't forget select() (WINSOCK), which uses the "Pointer = 0 is infinite", "Pointed to value is 0 is 'poll'" semantics, too.

    It is a mess that there is nothing like a "standard".

    A side-note: An interesting remark from a co-worked of you, doron: http://blogs.msdn.com/oldnewthing/archive/2006/08/28/728349.aspx What do people in the kernel space think about this?

    - Spiro.
  • Anonymous
    August 28, 2006
    Phooey!  That was on my list of things to write about ;).  

    I totally agree with raymond.  If it is obvious (the name of the function implies the usage of the value), it is fine.  Otherwise with KMDF in the non obvious situations, we tried to give a BOOLEAN like value an enum with more declarative / easier to understand what they mean constant names.

    d