KMDF Timer Objects


A KMDF driver can use a timer object to request a callback at repeated periodic intervals or only once after a driver-specified amount of time has elapsed. Drivers use timers for a variety of purposes. For example:

  • The Pcidrv sample creates a watchdog timer to aid in link detection on its device and to check for hardware hangs.

  • The Serial sample creates several timers to time out read and write operations.

  • The Toastmon sample creates a periodic timer to send requests to its I/O target at regular intervals.

Every timer object is associated with an EvtTimerFunc callback. The framework adds the callback to the system's DPC queue when the timer expires.

If the device is powered down for idle or stopped to rebalance resources, the framework does not stop the timer. The driver can stop the timer in the self-managed I/O callbacks for the corresponding event. If the device is removed, the framework stops the timer before deleting the timer object.

Chapter 8, "I/O Flow and Dispatch," includes an example that shows how to use the self-managed I/O callbacks to manage a timer.

Timer Object Methods

Table 12-7 lists the methods that timer objects support.

Table 12-7: Timer Object Methods
Open table as spreadsheet

Method

Description

WdfTimerCreate

Creates a timer object.

WdfTimerGetParentObject

Returns a handle for the parent of the timer object.

WdfTimerStart

Starts the timer.

WdfTimerStop

Stops the timer.

To create a timer object, a driver calls WdfTimerCreate and passes a pointer to a WDF_TIMER_CONFIG structure and a pointer to a WDF WDF_OBJECT_ATTRIBUTES structure.

The following fields in the WDF_TIMER_CONFIG structure supply information about the timer:

  • EvtTimerFunc

    A pointer to a driver-supplied EvtTimerFunc callback function.

  • Period

    A time period, in milliseconds (ms). The framework calls the driver's EvtTimerFunc callback function repeatedly, whenever the specified number of milliseconds elapses. If this value is zero, the framework calls the callback function once, after the WdfTimerStart method's "due time" has elapsed. The time period cannot be a negative value.

  • AutomaticSerialization

    A Boolean value that, if TRUE, indicates that the framework will synchronize execution of the timer object's EvtTimerFunc callback function with callback functions from other objects that are children of the timer's parent device object. The synchronization scope for the parent device object must be either WdfSynchronizationScopeDevice or WdfSynchronizationScopeQueue.

The framework provides two functions to initialize the timer configuration structure:

  • WDF_TIMER_CONFIG_INIT sets up the configuration structure for a timer that has a single due time.

    This function takes as parameters a pointer to the WDF_TIMER_CONFIG structure and a pointer to the EvtTimerFunc callback that the framework should queue when the timer expires.

  • WDF_TIMER_CONFIG_INIT_PERIODIC sets up the configuration structure for a timer that expires at regular intervals.

    This function takes a time value that specifies the interval at which the timer expires in addition to the two parameters that are described for WDF_TIME_CONFIG_INIT.

Both of the initialization functions set the AutomaticSerialization field of the structure to TRUE.

Chapter 10, "Synchronization," contains more information about automatic serialization.

Time Periods

The Period field of the timer configuration structure and the DueTime parameter of the WdfTimerStart function require the time in different units, as follows:

  • The Period field requires the time in milliseconds.

  • The DueTime parameter for WdfTimerStart requires the time in system time units, which are 100-nanosecond intervals.

    DueTime can be an absolute time or a time that is relative to the current system time. For a periodic timer, the DueTime parameter specifies the first time that the timer fires. Thereafter, the timer fires at the intervals defined by the Period field.

    • An absolute time value is a positive value that specifies the number of 100-nanosecond intervals that have elapsed since 00:00, January 1, 1601.

    • A relative time value represents a change from the current system time. Relative time values are represented by negative numbers.

KMDF includes several functions that convert time values from one unit to another. You can also use these time conversion functions to set time-out values for I/O requests. Table 12-8 lists the time conversion functions.

Table 12-8: KMDF Time Conversion Functions
Open table as spreadsheet

Function name

Description

WDF_ABS_TIMEOUT_IN_MS

Converts a value in milliseconds to absolute time in system time units.

WDF_ABS_TIMEOUT_IN_SEC

Converts a value in seconds to absolute time in system time units.

WDF_ABS_TIMEOUT_IN_US

Converts a value in microseconds to absolute time in system time units.

WDF_REL_TIMEOUT_IN_MS

Converts a value in milliseconds to a relative time in system time units.

WDF_REL_TIMEOUT_IN_SEC

Converts a value in seconds to a relative time in system time units.

WDF_REL_TIMEOUT_IN_US

Converts a value in microseconds to a relative time in system time units.

For example, to set a timer that expires in 5 seconds, the driver passes WDF_REL_TIMEOUT_IN_SEC(5) to WdfTimerStart.

EvtTimerFunc Callback Function

The EvtTimerFunc callback function is a DPC that that runs at DISPATCH_LEVEL. The framework adds this function to the end of the system's DPC queue when the timer expires, and the function runs when it reaches the head of the queue.

The EvtTimerFunc callback has the following prototype:

 typedef VOID     (*PFN_WDF_TIMER) (         IN WDFTIMER    Timer     ); 

where Timer is the handle to the timer object that triggered the callback.

Because the function runs at DISPATCH_LEVEL, it cannot take any actions that would cause a page fault. If the timer function must take actions that must be done at PASSIVE_LEVEL, the function should create a work item object and queue the associated work item callback to perform those tasks.

Chapter 15, "Scheduling, Thread Context, and IRQL," contains more information on work items and the rules for running at DISPATCH_LEVEL.

Example: Using a Timer Object

The Toastmon sample uses a timer to send periodic requests to each of the driver's I/O targets. Each time the driver creates an I/O target object, it also creates a timer.

Listing 12-12 shows how the driver creates and starts this timer. The sample code in the listing is adapted from the Toastmon.c file.

Listing 12-12: Creating and starting a timer object

image from book
 NTSTATUS                    status = STATUS_SUCCESS; PTARGET_DEVICE_INFO         targetDeviceInfo = NULL; WDFIOTARGET                 ioTarget; WDF_OBJECT_ATTRIBUTES       attributes; WDF_TIMER_CONFIG            wdfTimerConfig; // Create a periodic timer to post requests to the I/O target. WDF_TIMER_CONFIG_INIT_PERIODIC(&wdfTimerConfig,                                Toastmon_EvtTimerPostRequests,                                PERIODIC_TIMER_INTERVAL); //ms WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, TIMER_CONTEXT); // Set the IoTarget as the parent of the timer attributes.ParentObject = ioTarget; targetDeviceInfo = GetTargetDeviceInfo(ioTarget); status = WdfTimerCreate(&wdfTimerConfig,                         &attributes,                         &targetDeviceInfo->TimerForPostingRequests                         ); if(!NT_SUCCESS(status)) {     WdfObjectDelete(ioTarget);     return status; } GetTimerContext(targetDeviceInfo->TimerForPostingRequests)->IoTarget = ioTarget; // Start the timer. WdfTimerStart(targetDeviceInfo->TimerForPostingRequests,               WDF_REL_TIMEOUT_IN_MS(1)); 
image from book

As the listing shows, the driver calls WDF_TIMER_CONFIG_INIT_PERIODIC to configure a periodic timer. The driver passes a pointer to a WDF_TIMER_CONFIG structure, a pointer to its EvtTimerFunc callback, and the PERIODIC_TIMER_INTERVAL constant, which the driver defined in the Toastmon.h header file as 1000.

The driver then initializes an object attributes structure for the timer object by specifying the type of the context area for the timer. The driver uses the timer object's context area to hold a handle to the I/O target object with which the timer is associated. The driver sets the ParentObject field of the attributes structure to the I/O target so that the I/O target object cannot be deleted while EvtTimerFunc is running.

Next, the driver gets a pointer to the context area for the I/O target object by calling the driver's GetTargetDeviceInfo accessor function. Then the driver calls WdfTimerCreate, passing the initialized configuration structure, the initialized attributes structure, and a pointer to the location in the I/O target object's context area in which the driver stores the timer object handle. If WdfTimerCreate fails, the driver deletes the I/O target object.

The driver stores the I/O target object handle in the timer object's context area and then starts the timer. WdfTimerStart takes a handle for the timer object and a due time in system time units. The driver specifies a 1-ms due time, which causes the framework to queue the EvtTimerFunc for the first time after 1 ms elapses. Thereafter, it queues the timer at the 1-second intervals (1000 ms) that the driver set in the configuration structure. The driver uses 1 ms for the initial due time because 1 ms is the smallest time resolution that Windows can handle.

The driver stops the timer when the framework notifies it about a query-remove or remove request for the I/O target. Listing 12-13 shows how the driver stops and deletes the timer.

Listing 12-13: Stopping and deleting a timer object

image from book
 targetDeviceInfo = GetTargetDeviceInfo(IoTarget); WdfTimerStop(targetDeviceInfo->TimerForPostingRequests, TRUE); WdfWorkItemFlush(targetDeviceInfo->WorkItemForPostingRequests); WdfObjectDelete(IoTarget); 
image from book

The driver calls WdfTimerStop with a handle to the timer object and a Boolean value that, if TRUE, specifies that WdfTimerStop should not return until all of the driver's queued EvtTimerFunc callbacks and any other DPCs have run to completion. The EvtTimerFunc callback creates a work item to perform processing at PASSIVE_LEVEL. Therefore, no more work items can be queued after WdfTimerStop returns, so the driver can flush the work item queue. The sample then deletes the I/O target object, which is the parent to both the timer and the work item.

When the driver deletes the parent I/O target, the framework waits for the timer and the work items to complete before it deletes them, so it might seem unnecessary for the sample to stop the timer and flush the work items. However, the framework does not guarantee the order of deletion for multiple children of the same parent when the parent is deleted. The driver explicitly stops the timer and flushes the queue so that the framework can safely delete these two objects in either order.




Developing Drivers with the Microsoft Windows Driver Foundation
Developing Drivers with the Windows Driver Foundation (Pro Developer)
ISBN: 0735623740
EAN: 2147483647
Year: 2007
Pages: 224

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net