先转一段,具体出处忘了:
驱动程序和应用程序的另外一个不同是运行驱动程序时系统并不创建专门的线程。取而代之的则是当某一个线程被激活的时候由系统来决定是否执行驱动程序里的子程序
当一个硬件中断发生的时候我们不可能预测到此时正是哪个线程。同样,想象一下你在游乐园正在观察旋转木马。其上的木马就类似于系统中的线程,我们将离你最近的木马称为当前线程。现在我们假设当你无意中听到有人说“That’s awesome, dude.”时你决定用你的相机拍照(在我游乐园的经验中,这不会有长时间的等待),你不能预测到在你的快照中哪只马是当前的。当硬件发生中断的时候哪个线程正在执行中也是不可预测的。我们称其为任意线程,我们所说的都是一个任意线程。
当系统决定调用你驱动程序中的子程序时,它常常运行着一个任意线程上下文。线程的上下文会是任意的——例如,当你的中断服务程序获得控制权。如果你制定一个dpc,那么运行你dpc程序的那个线程将会是任意的。如果你排队等待irp,你的StartIo程序会被一个任意线程调用。事实上,如果一些在你的堆栈外驱动程序发送给你一个irp,你也不得不假设线程上下文是任意的。这通常会是给存储驱动程序的场合,因为一个文件系统驱动程序会成为对读写负责的代理。
系统不总是在任意线程上下文中执行驱动程序代码。一个驱动程序可以通过调用PsCreateSystemThread函数来创建自己的系统线程。驱动程序也可以让系统在有相关操作项目的系统线程中回调它。在这些情况下,我们认为线程上下文不是任意的。我将在第14章讨论系统线程的结构和工作项目。
不是任意的进程上下文的另一种情况发生在当应用程序放出一个了引起I/O管理器直接给驱动程序发送irp的API调用时。你能知道你处理的每一个irp是否和你写的驱动有关
有两个理由让你关心进程上下文是否是任意的。首先,驱动程序不应该阻塞任意线程;虽然你激活了一些其他的线程,但是这不公平。第二个理由是当驱动程序创建了一irp,并将其发送给一些其它的驱动程序。我会在第五章充分讨论,虽然你需要在一任意线程中创建一种irp(异步irp),但你可能却在非任意的线程内创建了不同种类的irp(同步irp)。I/O管理器将同步种类的irp连接到你创建irp的线程上。若该线程结束了其也会自动地删去irp。但I/O管理器不将任何异步irp连接到任何线程上,你创建的一个异步线程可能不会执行你要做的任何I/O操作。并且由于线程的偶然终止还会导致系统取消irp错误。所以其不行。
//转贴到此完毕
在linux中,中断处理中不能睡眠,但是在驱动里面确实是可以睡眠的,sleep_on的调用到处都是以至于我们没有人特意关注这个问题,这就是从 unix继承的:一切都是同步的;但是到了windows却变成了另一番景象,windows中,一切都是异步的,这并不是仅仅是一句话而 已,windows的中断优先级控制执行绪以及除了中断之外的非线程执行绪决定了windows不能是同步的,当然有个先有鸡先有蛋的问题,但是这个问题 没有意义。
实际上不能说中断中就不能睡眠,而正确的说法应该是没有线程(进程?)上下文的执行绪都不能睡眠,否则:1.没有自己上下文可恢复;2.对其他被借用上下 文的线程不公平。那么我们看看windows的情况,windows引入了apc,dpc等一系列执行绪,dpc在低于硬件中断高于一般进程的优先级运行,根据windows基于中断优先级的抢占原理,只有硬件中断可以抢占它,换句话说就是硬件中断完毕之后它必执行(因为此时它的优先级次高),这不同于 linux,linux的软中断执行不是靠一条原理控制的而是代码写死的。既然硬件中断没有上下文随时借用别的线程的上下文,那么dpc也没有上下文了, 所以它执行时,线程上下文是不确定的,因此dpc也不能睡眠。
windows的驱动设计有了这个要求真是不爽,但windows驱动开发框架(ddk函数)已经帮程序员做好了一切,比如irp包是基于堆栈的,它由 io管理器管理,io完成例程就是在dpc被调用的(io分发例程必须在低于apc,dpc的中断优先级运行,因为只有这样它才可以睡眠,阻塞当前线程, 因为睡眠就要调度,而调度例程和dpc例程的中断优先级相同),而且都是异步的,不会睡眠。
这个理论解释了为何在windows驱动里面全是异步唤醒,只有在线程上下文才可以睡眠。windows里面在dpc里置位一个事件,可能irp的异步操 作都将在dpc进行,而dpc会调用io分发函数,这些分发函数都得是异步的;看看linux异步io,每次都重试,重试意味着可能再次受阻,任何读写函 数都是同步的,因为它敢,因为它确实在线程上下文(当前线程或者内核工作队列线程)。