基于 Windows NT 的 Microsoft 操作系统设计用于在单处理器和对称多处理器(SMP)平台上统一运行,内核模式驱动程序也应如此设计。
在任何 Windows 多处理器平台中,存在以下条件:
所有 CPU 都是相同的,所有处理器或者没有处理器必须具有相同的协处理器。
所有 CPU 共享内存并具有对内存的统一访问权限。
在 对称 平台中,每个 CPU 都可以访问内存、中断和访问 I/O 控制寄存器。 (相比之下,在 非对称 多处理器计算机上,一个 CPU 对一组从属 CPU 执行所有中断。
若要安全地在 SMP 平台上运行,作系统必须确保在一个处理器上执行的代码不会同时访问和修改另一个处理器正在访问和修改的数据。 例如,如果最低级别的驱动程序 ISR 正在处理一个处理器上的设备中断,则当设备在另一个处理器上同时中断时,它必须具有对设备寄存器或关键驱动程序定义数据的独占访问权限。
此外,在单处理器计算机中序列化的驱动程序的 I/O 操作可以在多处理器(SMP)计算机中重叠。 也就是说,处理传入 I/O 请求的驱动程序例程可以在一个处理器上执行,另一个与设备通信的例程在另一个处理器上并发执行。 无论内核模式驱动程序是在单处理器计算机还是对称多处理器计算机上执行,都必须同步对驱动程序例程之间共享的任何驱动程序定义数据或系统提供的资源的访问,以及同步对物理设备的访问(如果有)。
Windows NT 内核组件导出一种称为 旋转锁的同步机制,驱动程序可以使用该机制保护共享数据(或设备寄存器)免受在对称多处理器平台上并发运行的一个或多个例程的同时访问。 内核强制实施有关使用旋转锁的两个策略:
在任何给定时刻,只有一个例程可以保留特定的旋转锁。 在访问共享数据之前,必须引用数据的每个例程必须首先尝试获取数据的旋转锁。 若要访问相同的数据,另一个例程必须获取旋转锁,但在当前持有者释放旋转锁之前,无法获取旋转锁。
内核将 IRQL 值分配给系统中的每个旋转锁。 仅当例程在旋转锁的分配 IRQL 上运行时,内核模式例程才能获取特定的旋转锁。
这些策略可防止一个通常在较低 IRQL 上运行但当前持有旋转锁的驱动程序例程被一个更高优先级且尝试获取相同旋转锁的驱动程序例程抢占。 因此,避免死锁。
分配给旋转锁的 IRQL 通常是可以获取旋转锁的最高 IRQL 例程。
例如,最低级别的驱动程序 ISR 经常与驱动程序的 DPC 例程共享状态区域。 DPC 例程调用由驱动程序提供的 关键代码段 例程来访问共享区域。 保护共享区域的旋转锁的 IRQL 等于设备在发生中断时的 DIRQL。 只要关键节例程保留旋转锁并访问 DIRQL 上的共享区域,ISR 就不能在单处理器或 SMP 计算机中运行。
在单处理器机器上无法运行ISR,因为设备中断已被屏蔽,正如Always Preemptible and Always Interruptible中所述。
在 SMP 计算机中,ISR 无法获取保护共享数据的旋转锁,而关键部分例程保留旋转锁并访问 DIRQL 上的共享数据。
一组内核模式线程可以通过等待某个内核的调度程序对象(事件、互斥体、信号灯、计时器或其他线程)来同步对共享数据或资源的访问。 但是,大多数驱动程序不会设置自己的线程,因为它们在避免线程上下文切换时具有更好的性能。 每当时间紧迫的内核模式支持例程和驱动程序在 IRQL = DISPATCH_LEVEL 或 DIRQL 上运行时,它们必须使用内核旋转锁来同步对共享数据或资源的访问。