A properly designed and implemented driver will run correctly on both single-processor and multiprocessor systems. Because Windows is a fully preemptible operating system, most of the problems commonly observed on multiprocessor systems will eventually occur on single-processor systems, too.
Here are a few guidelines to help you develop drivers that operate properly and perform well on both single-processor and multiprocessor architectures:
· Assume that every driver will run on multiprocessor systems.
· Test every driver on as many different hardware configurations as possible. Always test drivers on multiprocessor systems to find errors that are related to locking, synchronization, and concurrency.
· Identify data and memory locations that are shared and might be accessed concurrently. Use locks to ensure that all potentially concurrent accesses occur serially.
· Use the simplest synchronization technique that meets your needs. Use interlocked operations and spin locks to perform atomic operations.
· Protect against compiler and processor reordering when required.
· Use standard Windows synchronization mechanisms whenever possible. They have implied memory barriers and are guaranteed to work on all supported hardware platforms.
· Write platform-neutral code. Do not create special cases in code for architecture-specific reordering scenarios.
· Use Driver Verifier and CUV to test for synchronization and locking problems.
· Use Kernrate, KrView, and (on Windows Vista) DevCon to collect performance data on multiprocessor systems.
Resources
General multiprocessor information:
Inside Microsoft Windows 2000, Third Edition Solomon, David A. and Mark Russinovich. Redmond, WA: Microsoft Press, 2000.
Kernel-Mode Driver Architecture Reference Standard Driver Routines Driver Support Routines
Driver Development Tools Tools for Testing Drivers
Debugger extensions:
Debugging Tools for Windows http://www.microsoft.com/whdc/DevTools/Debugging/default.mspx
Additional Tools:
Windows Resource Kit http://www.microsoft.com/windows/reskits/default.asp
[1] Called with any PnP minor IRP code.
[2] Includes all driver dispatch routines except DispatchPower and DispatchPnP.
[3] Called with the minor IRP code IRP_MN_SET_POWER or IRP_MN_QUERY_POWER and Parameters.Power.Type set to SystemPowerState.
[4] Called with the minor IRP code IRP_MN_SET_POWER or IRP_MN_QUERY_POWER and Parameters.Power.Type set to DevicePowerState.
[5] Cancel routine is set in IoSetCancelRoutine and IoStartPacket.
[6] Called with the PnP minor IRP code IRP_MN_START_DEVICE.
[7] Called with any PnP minor IRP code except IRP_MN_START_DEVICE.
[8] Can be concurrent if driver supports more than one device. StartIo can be called any time after IRP_MN_START_DEVICE has completed for the target device.
[9] Includes all Dispatch routines except DispatchPnp and DispatchPower.
[10] Minor IRP codes IRP_MN_CANCEL_REMOVE_DEVICE, IRP_MN_CANCEL_STOP_DEVICE, IRP_MN_QUERY_REMOVE_DEVICE, IRP_MN_QUERY_STOP_DEVICE, IRP_MN_REMOVE_DEVICE, IRP_MN_START_DEVICE, IRP_MN_STOP_DEVICE, or IRP_MN_SURPRISE_REMOVAL.
[11] Called with minor IRP code IRP_MN_SET_POWER or IRP_MN_QUERY_POWER and Parameters.Power.Type set to SystemPowerState.
[12] Called with minor IRP code IRP_MN_SET_POWER or IRP_MN_QUERY_POWER and Parameters.Power.Type set to DevicePowerState.
[13] Cancel routine is set by a call to IoSetCancelRoutine or IoStartPacket.
[14] The InterruptService routine (ISR) cannot be called until IoConnectInterrupt has completed for the device, typically during processing of an IRP_MN_START_DEVICE request. The ISR can be called concurrently while the interrupt is connected.
[15] DispatchPnP can be called with state-change IRPs until IRP_MN_REMOVE_DEVICE has been completed.
[16] StartIo routine can be made noncancelable in a call to IoSetStartIoAttributes.
[17] Depends on the type of driver. In a WDM driver, they cannot be concurrent because the driver disconnects interrupts before Unload is called. In a legacy driver, they can be concurrent because the driver disconnects interrupts in the Unload routine.
[18] Includes Dispatch routines for all IRP major function codes except IRP_MJ_PNP, IRP_MJ_POWER, IRP_MJ_CREATE, IRP_MJ_CLOSE, and IRP_MJ_CLEANUP.
[19] Cancel routine can be set by a call to IoSetCancelRoutine or IoStartPacket.
[20] Support of cancellation of IRP_MJ_CREATE requests is planned for Windows Vista.