當(dāng)驅(qū)動程序處理IRP的時候,它可能立刻完成,也可能在中斷里才能完成,比如說,往硬件設(shè)備發(fā)出一個請求(通常可以是寫I/O port),當(dāng)設(shè)備完成操作的時候會觸發(fā)一個中斷,然后在中斷處理函數(shù)里得到操作結(jié)果。Windows有兩類中斷,硬件設(shè)備的中斷和軟中斷,分成若干個不同的優(yōu)先級(IRQL)。軟中斷主要有兩種:DPC(Delayed Procedure Call)和APC(Asynchronous Procedure Call),都處于較低的優(yōu)先級。驅(qū)動程序可以為硬件中斷注冊ISR(Interrupt Service Routine),一般就是修改IDT某個條目的入口。同樣,操作系統(tǒng)也會為DPC和APC注冊適當(dāng)?shù)闹袛嗵幚砝蹋ㄒ彩窃贗DT中)。值得指出的是,DPC是跟處理器相關(guān)的,每個處理器會有一個DPC隊(duì)列,而APC是跟線程相關(guān)的,每個線程會有它的APC隊(duì)列(實(shí)際上包括一個Kernel APC隊(duì)列和User APC隊(duì)列,它們的調(diào)度策略有所區(qū)別),可以想象,APC并不算嚴(yán)格意義上的中斷,因?yàn)橹袛嗫赡馨l(fā)生在任何一個線程的上下文中,它被稱為中斷,主要是因?yàn)镮RQL的提升(從PASSIVE到APC),APC的調(diào)度一般在線程切換等等情形下進(jìn)行。當(dāng)中斷發(fā)生的時候,操作系統(tǒng)會調(diào)用中斷處理例程,對于硬件設(shè)備的ISR,一般處理是關(guān)設(shè)備中斷,發(fā)出一個DPC請求,然后返回。不在設(shè)備的中斷處理中使用太多的CPU時間,主要考慮是否則可能丟失別的中斷。由于硬件設(shè)備中斷的IRQL比DPC中斷的高,所以在ISR里面DPC會阻塞,直到ISR返回IRQL回到較低的水平,才會觸發(fā)DPC中斷,在DPC中斷里執(zhí)行從硬件設(shè)備讀取數(shù)據(jù)以及重新請求、開中斷等操作。ISR或者DPC可能在任何被中斷的線程上下文(arbitrary thread context)執(zhí)行,事實(shí)上線程的上下文是不可見的,可以認(rèn)為是系統(tǒng)借用一下時間片而已。
       總的來說,Windows的異步I/O架構(gòu)中,主要有兩種動力,一是發(fā)起請求的線程,一部分內(nèi)核代碼會在這個線程上下文執(zhí)行,二是ISR和DPC,這部分內(nèi)核代碼會在中斷里完成,可能使用任何一個線程的上下文。而調(diào)度常見使用回調(diào)和事件(KEVENT),比如說在往下一層的驅(qū)動程序發(fā)出請求的時候,可以指定一個完成例程Completion Routine,當(dāng)下層的驅(qū)動完成這個請求的時候會調(diào)用這個例程,而往往在這個例程里,就是簡單的觸發(fā)一下一個事件。
      另外可以順便提一下Linux。Linux 2.6也有類似的中斷機(jī)制,它有更多的軟中斷優(yōu)先級,即不同優(yōu)先級的softirq,而類似于DPC,Linux也提供了專門的軟中斷,對應(yīng)DPC的就是tasklet。Linux沒有一個像windows這么一致的層次驅(qū)動程序架構(gòu),所以它的異步I/O稍微粗糙一些,主要是通過以前的一些阻塞點(diǎn),現(xiàn)在直接返回-EIOCBRETRY,而讓調(diào)用者在合適的時機(jī)繼續(xù)重試。在這個方法中,可以認(rèn)為整個操作由一個函數(shù)完成,每次操作有進(jìn)展時,都把這個函數(shù)從頭執(zhí)行一遍,當(dāng)然已經(jīng)完成的部分就不會再有實(shí)際的I/O。這樣的最大好處是原有的文件系統(tǒng)和驅(qū)動程序不用完全重寫。而對于同步調(diào)用,只要阻塞就可以了,這樣對系統(tǒng)的修改較小。這時候,要提供POSIX aio的語義,就可能需要提供一些用戶線程來完成重試的過程了(回想Windows可以通過中斷和DPC完成的)。而對于Solaris,也是類似的處理,如果設(shè)備支持異步I/O,那就通過中斷可以完成,否則就使用內(nèi)部的LWP來模擬。

                以上內(nèi)容摘自 http://blog.csdn.net/emag_cpp/archive/2005/02/01/276301.aspx