在windows操作系統內核中,首先要明白四個概念,apc(異步過程調用),dpc(延遲過程調用),irp(io請求包)以及基于優先級的搶占式調度,下面分別解釋:
1.apc。 異步過程調用類似于linux下的信號,只不過信號處理函數的執行需要兩步:設置和觸發,而apc則只有一步,只需要將apc回調函數排入線程的apc對 列,它就總會被執行的。apc對列對于每個線程有兩個,一個是用戶空間的apc對列,一個是內核空間的apc對列,apc函數運行在apc優先級上,它一 般高于用戶線程的優先級。
2.dpc。延遲過程調用一般用于中斷的后期處理。中斷可在任何進程(線程)的上下文里面運行,而且一般情況下中斷處理 函數要關閉相應中斷,以防重入,為了使這種不確定的情況時間最小化,windows只會在中斷處理函數里面呆一小會,然后排隊一個dpc,從而退出中斷,dpc在低于isr的優先級運行,因此它可被硬件中斷中斷。
3.irp。這在windows里是一個異常重要的概念,它直接導致 windows的設計理念和類unix以及unix的設計理念的不同。一個irp封裝了一個io操作過程,它的內部是一個棧結構,每個棧幀代表一個驅動程 序模塊,其中封裝了此驅動的回調函數,irp就是一級一級往下層驅動傳遞從而完成一個io操作。
4.基于優先級的搶占式調度。這個是 windows下的調度策略,它完全基于優先級(還有時間片,但不影響什么,時間片對所有進程的策略一樣),而不是其它。如果有更高優先級線程就緒,那么它將馬上搶占當前線程。就連中斷都有自己優先級,呵呵,當然它是最高的...windows的響應性依賴于動態優先級提升,但是這就牽扯到別的方面了,和這篇文章的主題不對,因此不討論。
明白了上面的概念以后,我們就可以繼續了。
windows的io操作步驟如下:
1.應用程序調用ReadFile函數
2.ntdll.dll將用戶請求陷入內核空間繼續處理,由io管理器接管
3.io管理器創建一個irp,然后根據用戶請求填充其字段,接著將其交給最上層驅動程序
4.驅動程序一層一層將irp傳給硬件設備后一層層返回。注意,每往下傳遞一層都要注冊io完成回調。
到這里,如果是異步調用,那么就可以返回用戶空間處理了,如果是同步的,則在io管理器那里被阻塞,io操作還沒有完,接著往下看:
5.硬件操作完成,產生中斷,中斷排隊一個dpc后返回
6.dpc運行,調用驅動的完成例程
7.每層的完成例程相繼被調用,控制流一層層的返回給io管理器
8.將ReadFileEx中的用戶apc排隊(異步情況下),這個apc將在不長的時間內被調用,因為它的優先級高于用戶線程。
以 上就是windows的io流程,可見,irp的自洽性與獨立性使得一切成為可能,irp包含了足夠的信息足以使io操作脫離線程環境,這也是 windows內核整體的設計理念----模塊化。windows的優先級控制非常巧妙,有個概念叫“中斷請求級”,就是將cpu的運行分成了不同的級別分別為:PASSIVE_LEVEL---DISPATCH_LEVEL---PROFILE_LEVEL,windows將任務在這幾個優先級中分配, 使得操作變得簡單,它基于一條原則:一旦某CPU執行在高于PASSIVE_LEVEL的IRQL上時,該CPU上的活動僅能被擁有更高IRQL的活動搶先。這條原則保證了很多操作可以安全進行,比如io派遣例程運行在PASSIVE_LEVEL上,而從irp對列拽一個irp以求處理的dpc運行在DISPATCH_LEVEL,這樣就不會有任何派遣例程打擾一個irp的操作,從而省去了鎖的操作,在一個硬件中斷中,運行在硬件中斷優先級的cpu將一個dpc排入該cpu對列,中斷完畢后cpu降至DISPATCH_LEVEL優先級,dpc得以執行...優先級控制正是windows的一大特色。
綜上我們明白了windows異步io的幾大要素:1.獨立自洽的irp結構;2.優先級的控制。進一步抽象到了windows的設計思想:模塊化。windows本身是微內核系統,而微內核就是模塊化的。
反觀linux的異步io,其實現就是在原來同步阻塞點直接返回,然后在以后重試,負責重試的在老內核不支持異步io的情況下是一系列用戶線程,而在 2.6以后是工作隊列,而工作隊列本質上是一個內核線程,由此可見,linux中并沒有和windows對應的dpc的概念,如果非要拉出來一個長得像的,那就是softirq了,但是也就僅僅執行點像,實際上softirq在大多數情況下是由softirqd內核線程執行的,為的就是不讓 softirq(dpc?)長期占據處理器,試想一個多網卡的高負載的服務器,softirq幾乎占據了很大一塊cpu資源,于是乎,不管什么,不管你多 特殊,一律統一接收線程調度程序的調度,這就是公平。而在windows中卻顯得不那么公平,當然也可以在windows驅動里面自覺地建立內核線程,但是那畢竟不是系統提供的功能啊!
linux和unix一脈相承,簡單,公平,統一可能就是它們的品質,一切都是文件,一切接受調度,接口統一;windows相比就顯得有些花花綠綠了, 但我還是很欣賞它的優先級控制方案。傳統unix本質上是同步的,因為它簡單,受控性很好,可預測,所以它穩定,如果在內核一個函數阻塞了,進程不能繼續了,unix的做法就是直接調度schedule,而windows的做法就是異步喚醒,然后調整優先級之類的,因為它本質就是異步的。linux最近吸取了unix和windows的優點,所以直接調度和異步喚醒在內核均可見到,不錯不錯,但是有些亂,變化太快,我很擔心如果linux沒有一個根本是設 計理念,隨著它復雜性增加,代碼膨脹,它會不會失控?!
內核穩定性和它們的設計理念有關嗎?僅說一點,windows是基于優先級的,dpc在DISPATCH_LEVEL 運行,除了硬中斷用戶進程無法將它搶占,那么如果它在內核睡眠的話.....而linux一視同仁,內核線程和用戶線程統一被調度,當然就不會頻繁掛機了....這僅僅從線程化軟中斷角度講,實際上linux下的softirq也是不能睡眠的,因為你不能保證每個softirq都在內核線程上下文執行,不過這并不是問題,現在的新內核都將中斷給線程化了,還有什么做不到呢?windows的中斷請求優先級實際上是一種抽象,將實際執行硬件或軟件和執行本身分離,這是非常不錯的,簡簡單單的一個優先級提升或降低加上一個基本原則就可以代替linux的一大堆加鎖解鎖禁用搶占之操作。
不管是linux還是windows,其本身都運用了統一,簡單的思想,只不過用的地方不同,linux提供的vfs,盡量線程化,windows的優先級控制,對象化.....
windows和linux不愧是兩大巨猛系統