windows的IO管理器內核實現機制原理分析

IO管理器的任務就是管理IO,本質上windows的IO操做都是異步的,這是由IO流的分層下遞和IRQL共同決定的,效果就是IO流被處理的每個步驟均可能在任意線程上下文中進行,那麼若是最下面的驅動完成了一個irp,這個怎麼讓上面的驅動知道呢?固然方法不少,好比上層驅動等待在一個   event上,而microsoft的做法顯然更好,就是爲每個irp流經的每個設備提供了一個選擇,該設備的驅動能夠提供一個回調函數,以便下層驅動完成請求的時候通知該層,這就是IO完成回調函數,按照常規理解,這個函數應該由下層的驅動調用,而實際上這樣作的話,實現就不是那麼「結構化」了, 驅動的開發者就必須負責去手工調用該函數,失去了回調原本的含義,增長了驅動開發者的負擔,所以這個回調函數就由IO管理器來調用,這裏的說法僅僅是按照模塊化思想來的,在整個windows內核中你實際上看不到一個叫作IO管理器的模塊的,所謂的IO管理器就是一系列函數接口,對於IO完成回調函數的調用,你只須要調用一個IofCompleteRequest就能夠了,而這個接口的實現就是IO管理器的重要內容,那麼它是怎麼實現的呢?若是不看ReactOS的代碼,也不反彙編windows內核的話,還有一種狀況可以獲得它的實現,那就是本身想,我就是這麼幹的,沒想到還真蒙對了。windows

    在分層的驅動逐次往下層的設備遞交irp的過程當中,只要有一個分發函數調用了IofCompleteRequest,那麼該irp就不會再往下走了,而是順着來的方向的反方向逐個的調用irp棧上的IO完成回調函數,所以IofCompleteRequest的實現首先就是遍歷全部的irp棧幀,而後在每個上執行其IO完成回調函數便可,這只是最簡單的方式,windows內核的邏輯也是這麼來的,可是每每本身能想到的都是最簡單的,擴展開來的話會有不少本身想不到的,好比:有一種狀況就是irp棧某一層完成了io,IO管理器調用了上層的io完成回調,接下來該回調返回之後,IO管理器會接着調用上上層的io完成回調,然而若是這個上層的io完成回調中若是一個數據沒有準備好,而上上層io完成回調中又須要這個數據的話,這就會引發問題,IO管理器直接 調用了上上層的io完成回調,而實際上這個上層的io尚未完成呢(一個數據沒有到位)。以上這種狀況是很常見的,畢竟windows內核是一個本質上異步的操做系統內核,一個irp到達某個層次後可能爲了實現某項功能會進行一些別的操做,好比查詢一些信息,好比和別的內核模塊進行交互,這都會產生另外的 irp,而這些irp是和上層沒有關係的,是在本層產生並下發的,所以若是這些irp不完成,那個原本的irp也就算沒有完成,所以雖然下層完成了這個原本的irp,只由於這些額外的咱們本身在本層生成的irp尚未完成,這就意味着IO完成不能這麼簡單的逆流而上,實際上最簡單的方式就是告訴IO管理器,也就是告訴IofCompleteRequest不要繼續逆流而上了,等到時機成熟的時候,我本身逆流而上,這就是IO完成回調函數 STATUS_MORE_PROCESSING_REQUIRED返回值的含義,IofCompleteRequest一旦接收到某個回調函數的返回值是這個,那麼就終止循環,而後退出IO管理器,等到這個層次的全部數據都準備好以後,該驅動自行調用IofCompleteRequest,這將重複一樣的過程,只是起點變化了,不是最底層的驅動了,而是該層驅動,也就是由於數據而等待的驅動,數據能夠在io完成中被準備好,也能夠是別的,這就是另外的話題了。異步

    最終irp會回到它生成的地方,到這裏以後,大多數狀況下仍然是任意線程上下文,由於最底層驅動的完成是靠中斷觸發,因此一系列的逆流而上就是在DPC中執行的(DPC在cpu的隊列中排隊,爲了延遲執行硬中斷任務,而APC在線程隊列中排隊,執行線程上下文中執行的任務),所以爲了將完成消息通知到發出請求的線程,就須要將最後的irp層次的io完成回調函數排入到該線程的apc隊列中,而後最終在該線程的上下文中被執行,實際上排入apc隊列的是 IopCompleteRequest函數。底層驅動不能立馬完成的irp,返回時必定要設置pending狀態,這樣上層才能夠正確處理完成回調函數, 注意,這個pending和STATUS_MORE_PROCESSING_REQUIRED的含義是不一樣 的,STATUS_MORE_PROCESSING_REQUIRED是本身來處理接下來的完成回調,而pending則是指示io尚未完成,但是完成 回調卻要調用,爲了防止阻塞,真正的完成操做將在dpc/apc中進行。模塊化

相關文章
相關標籤/搜索