Can I use a Controller Object for serialization and synchronization?
Serialization Using Controller Objects
Windows NT offers several mechanisms for synchronization and serialization. There are spin locks, which provide high priority mutual exclusion; the "kernel dispatcher" objects (timers, events, semaphores, mutexes), which interact with the scheduler at passive level; and device queues, which provide a means for a device object to serialize processing of I/O requests. A lesser known, but very useful, synchronization object is the controller object, which has its own unique characteristics and usage.
A controller is intended to model a resource shared by several devices. The classic example is a disk controller that provides a single data channel for a set of disk drives. Although the individual drives operate independently, they must share the disk controller for operations that involve data transfer. Other operations, such as a head seek, do not require the disk controller's data channel. The device driver uses a controller object to represent the shared resource. When one of the disk drives requires the channel for a data transfer, it must first acquire the controller object representing the shared resource. If an operation on another drive needs the channel, it must wait until the operation on the first drive completes. The controller object provides this serialization mechanism.
To create a controller object, a device driver calls IoCreateController. The system returns a pointer to a controller object, or NULL if the operation fails. When the driver is unloads, or the controller is no longer neeed, the device driver destroys the object by calling IoDeleteController.
Acquistion of a controller object requires calling IoAllocateController. The semantics of this call are "Please call my callback routine when the controller object is free". If the controller object happens to be not busy when the device driver calls IoAllocateController, the system calls the callback routine supplied by the caller immediately on the same thread. If the controller object is busy, IoAllocateController puts the address of the callback routine on a queue, and returns to the caller immediately. This is very similar to calling IoStartPacket, which will cause a call to StartIo if the device is not currently processing an IRP, or will queue the IRP if the device is busy. Not surprisingly, these internal implementation of these two mechanisms share a common data structure, namely KDEVICE_QUEUE.
When the device driver completes the operation that required the shared resource represented by the controller object, it calls IoFreeController. If there is another callback request in the controller object's queue, the system dequeues the request and invokes the callback routine.
So, you can think of a controller object as a specialized type of queue. Each item in the queue consists of a callback routine and an associated parameter. The controller object is responsible for handling each item passed to it, either by immediately calling the callback or by queuing the request for later dispatching. The controller object queues a new item only when the resource it represents is busy. Initially not busy, the resource becomes busy when a device driver calls IoAllocateController. It becomes not busy when IoFreeController is called and the controller's queue is empty. The queuing mechanism implemented by a controller object guarantees that IoFreeController has been called between consecutive invocations of the callback. The driver gets serialized access to the resource without having to explicitly manage a queue.
If you are writing your driver with DriverWorks, use class KController to implement controller objects. This class encapsulates and simplifies the system services related to controllers, and enables you to make the callback routine a member of your device class, should you so choose.
As of this writing, Microsoft has removed the system services for controllers from WDM.H, the primary include file for Win32 Driver Model drivers. However, if you are using DriverWorks, this is not a problem. DriverWorks provides an implementation of KController for WDM that does not rely on the system services.