【Windows內核原理與實現】讀書筆記(二)

內容:43—51頁

處理器模式

  在Intelx86處理器上,段描述符有一個2位長度的特權級:0表示最高特權級,3表示最低特權級。Windows只使用0和3兩種特權級。特權級0表示CPU處於內核模式,3表示用戶模式。處理器有許多指令只能夠在特權級0的模式下使用,例如I/O指令,操縱內部寄存器(如GDT、IDT、MSR)的指令等。在Windows中,當處理器位於用戶模式下,處理器只能訪問當前進程的地址空間。而在內核模式下,處理器不僅可以訪問當前進程的地址空間,還可以訪問系統地址空間。

  一個指令流(線程)在執行時,出現以下情況會發生模式切換:

    1、用戶模式代碼觸發了異常;

    2、用戶模式代碼在執行時發生了中斷。

    3、執行特殊的模式切換指令。

內存管理

         Windows系統中,0~2GB是進程地址空間,2GB~4GB是系統地址空間。爲了有效管理2GB的系統地址空間,Windows在初始化時將這2GB劃分爲一些固定的區域,各個區域有專門的用途。Windows內核使用了一組全局變量來記錄每個區域的邊界,系統地址初始化實際上是對這些全局變量的初始化,並相應地初始化每個區域。Windows的引導選項和系統配置(位於註冊表)可能會影響到某些區域的位置和大小。

         系統空間中主要區域包括:內核模塊鏡像,PFN數據庫、換頁內存池、非換頁內存池、會話空間、系統緩存區、系統PTE區域、系統視圖以及頁表等。

         Windows使用Intelx86的二級或多級頁表機制來訪問虛擬內存。翻譯過程涉及查詢頁目錄與頁表。如果頁表項指示的一個頁面未在物理內存中,則觸發頁面錯誤(page fault)異常。虛擬內存管理器通過頁面錯誤異常將已被換出到磁盤上的數據或代碼重新帶入物理內存,以供訪問。Windows利用頁表機制,實現了靈活的頁面交換算法,可以支持一個或多個頁面交換文件,同時也實現了內存頁面的寫時複製(copy-on-write)特性。

         在系統空間中,不同的區域使用不完全相同的內存頁面管理算法:

    1、非換頁內存池:初始化時已經被映射到物理頁面上,做法是按照不同的粒度,將空閒頁面鏈接起來。申請和釋放頁面的操作實際上是針對空閒鏈表來進行的。

    2、換頁內存池:Windows使用位圖來管理頁面的分配。

    3、系統PTE區域:這部分內存區域存放的並非PTE,而只是表示這部分地址範圍是以PTE的形式來管理的,把PTE當成資源來管理。

  Windows執行體在這些系統內存區域管理的基礎上,提供了一組更小粒度(8B的倍數)的內存池管理,包括執行體換頁內存池和執行體非換頁內存池。這些內存池通過空閒鏈表記錄下每個已申請頁面中的空閒內存塊;當釋放內存時,自動與相鄰的空閒內存塊合併以構成更大的空閒內存塊。內核的其他組件通過使用執行體暴露的API函數(例如ExAllocatePoolWithTag和ExFreePoolWithTag)來使用這些內存池。

 

  進程地址空間是隨進程一起被創建的,進程地址空間按照其虛擬地址是否被分配或者保留來進行管理,用戶模式代碼通過Windows API函數VirtualAlloc和VirtualFree來申請獲釋放地址範圍,而內核中的虛擬內存管理器通過一棵平衡二叉搜索樹來管理進程地址空間被使用的情況。樹中的每個節點VAD(虛擬地址描述符,Virtual Address Descriptor),描述了一段連續的地址範圍。

         在VAD中,有一種重要的節點類型爲內存區對象(section object),它是Windows平臺上兩個或多個進程之間共享內存的一種常見方式。內存區對象可以被映射到系統的頁面文件、可執行文件或者其他數據文件中,也可能被映射到物理內存中。內存區對象代表了一種物理存儲資源。

 

         內存管理器的另外一個重要功能是管理有效的物理內存。在Windows的系統地址空間中,保留了一個被稱爲PFN(Page frame number database,頁幀編號數據庫)的區域。每個物理頁面都對應PFN數據庫中的一項,此PFN項描述了該頁面的狀態。Windows支持8種狀態:活動、備用、已修改、已修改但不寫出、轉移、空閒、零化、壞狀態。活動是指此正在被某個進程或系統空間所使用,有一個對應的PTE指向該頁面。壞是指該物理頁面已檢測到硬件錯誤。

 

         工作集管理器要解決的是當系統中的進程需要使用大量內存時,內存管理器如何將有限的物理頁面分配給那些需要使用內存的進程。這裏的工作集是指一個進程當前正在使用的物理頁面的集合。每個進程都有一個工作集鏈表,其中每一項不僅記錄了物理頁面的編號,還記錄了其他屬性,包括了它的年齡。工作集管理器可以根據一些策略來選擇要修剪的進程。針對被選中的進程,選擇哪些頁面被換出到磁盤中,從而將物理頁面騰出來。工作集管理器運行在一個成爲平衡集管理器的線程中,每隔1s被觸發一次,當可用內存太低時,也會被觸發。平衡集管理器也會定期觸發進程/棧交換器(process/stack swapper)。進程/棧交換器是另一個單獨的線程,一旦被喚醒,就會將滿足特定條件的進程和棧換入內存或換出內存。

 

進程和線程管理

         Windows優先級分爲0-31,0表示系統優先級,爲最低優先級,僅用於零頁面線程;1-15爲動態優先級,在某些情形下線程的動態優先級可以在此範圍內進行微調;16-31爲實時優先級,用於處理一些實時處理任務。

         作業(Job)是一個執行體支持的內核對象,它使得一個或多個進程被當做一個整體來加以管理和控制。

         纖程(fiber)是一種用戶線程,它對於內核是不可見的,由kernel32.dll實現

 

中斷和異常

         中斷是處理器與外部設備打交道的重要途徑,異常是處理器的正常指令流在執行過程中產生的一些特殊事件,需要緊急處理才能繼續原來的指令流。它們都會打斷一個正常的指令流,但區別在於中斷的發生與當前指令流並無實質聯繫,而異常則是當前指令流執行的直接結果。中斷是異步的,異常是同步的。

         Intelx86採用同一套陷阱機制來處理中斷和異常,它利用IDT,將每個中斷或異常同一個處理該中斷或異常的服務例程聯繫起來。Windows在此硬件機制的基礎上,提供了一種更爲靈活的軟件機制,允許驅動設備程序爲特定的中斷向量添加它的中斷服務例程(ISR,Interrupt Service Routine)。一箇中斷向量允許連接多箇中斷對象(interrupt Object),這裏中斷對象是一種封裝了中斷服務服務例程的內核對象。因此,中斷髮生時,這些中斷對象中的中斷服務例程都有機會處理該中斷。同時,多個硬件設備也可以共享同樣的硬件中斷向量。

         中斷控制器(如APIC)允許設定每一個硬件中斷的優先級,但Windows中沒有使用中斷控制器的優先級,而是規定了一套軟件中斷優先級,稱爲中斷請求級別(IRQL,Interrupt Request Level)。在Intelx86系統中,Windows使用0~31表示IRQL,數值越大,優先級越高。處理器在運行時總有一個當前IRQL。如果發生中斷,中斷源的IRQL等於或低於當前級別,則該中斷被屏蔽,直到處理器的IRQL降下來爲止。IRQL=0表示普通線程,稱爲PASSIVE_LEVEL或被動級別,它的優先級最低,可被其他任何級別的中斷打斷。IRQL=1表示異步過程調用(APC,Asynchronous Procedure Call),稱爲APC_LEVEL。在一個線程中插入一個APC對象可以打斷該線程的執行;IRQL=2表示處理器正在做以下兩個事情之一:正在進行線程調度;正在處理一個硬件中斷的後半部分(不那麼緊急的部分),這被稱爲延遲過程調用(DPC)。因此,IRQL=2也被稱爲DISPATCH/DPC級別,也即DISPATCH_LEVEL。3~26是設備IRQL,27~31是一些特殊的硬件中斷,包括時鐘中斷,處理器間中斷等,它們都是硬件中斷。

         DPC是一個重要的概念。它往往用來執行一些相對於當前高優先級的任務來說不那麼緊急的事情,硬件中斷服務例程可以把一些相遇不緊急的事情放倒一個DPC對象中處理,從而縮短處理器停留在高IRQL的時間。在Windows內核中,DPC一個典型用法是定時器(Timer)的實現,在時鐘中斷服務例程,它負責處理中斷時間、系統時間,以及當前線程的時間信息等,並判斷系統的定時器數組中是否有定時器到期,若有則發出DISPATCH_LEVEL的軟中斷請求。定時器到期是在DPC交付(deliver)過程中處理的,定時器被當做一種特殊的DPC對象而交付執行。

         APC是線程相關的例程,只能夠在特定的線程環境中被執行,因此也一定在特定的地址空間中被執行。當一個線程獲得執行權時,它的APC例程會被立刻執行。這一特性使得APC非常適合於實現各種異步通知事件。例如,I/O的完成通知可以用APC來實現。

        

         在Intelx86處理器中,異常也是通過IDT分發的,在IDT表中,0~0x1f之間的中斷向量是Intel保留的,除了2號中斷向量保留給NMI(不可屏蔽中斷)意外,其它已經定義的中斷向量都是針對各種條件所引發的異常的。Windows爲所有的異常都提供了異常處理器,有些異常直接由系統內核處理,例如頁面錯誤(0x0e異常),由虛擬內存管理器接管,有些異常則需要交給當前線程或Windows子系統的代碼來處理。

         在內核模式下,異常分發器首先將異常交給內核調試器來處理,如果沒有內核調試器或者內核調試器沒有處理該異常,則嘗試分發到一個基於幀的異常處理器,它將異常處理器與“棧幀”關聯了起來,因此當發生異常時,異常分發器根據當前棧中的棧幀來查找與之關聯的異常處理器。如果未能找到這樣的異常處理器,則異常分發器則會將該異常再次交給內核調試器,如果這次異常扔未被處理,則被認爲是一個嚴重錯誤,系統崩潰。

         在用戶模式下,異常分發器首先判斷進程的調試端口是否有效,若有效,則發送消息至調試端口,然後等待應答,否則將異常交給內核調試器。如果仍然未得到處理,則將控制轉到用戶模式下,由用戶模式的異常分發器(ntdll中的KeUserExceptionDispatcher函數)尋找一個基於幀的異常處理器。如果未找到,則控制再次回到內核模式下。這一次,內核模式的異常處理器首先嚐試調試端口,若異常未被處理,則再嘗試當前進程的異常端口。連接進程異常端口的是Windows子系統。如果Windows子系統在異常處理的最後時刻仍有機會處理它所屬進程的異常,如果它也不能處理此異常,則該進程被終止。

 

同步

         現代操作系統中,由於多處理器、多核或者中斷等各種併發性因素的存在,同樣的代碼有肯呢過被開發執行,而數據也可能被併發訪問。在這些情況下,對於可能被併發訪問的數據進行必要的同步。根據執行環境中的IRQL大於APC_LEVEL或者等於PASSIVE_LEVEL,可以講同步機制分爲“不依賴與線程的同步機制”和“基於線程調度的同步機制”兩大類。

         當IRQL大於APC_LEVEL時,Windows提供的典型的同步機制如下:

  • 提升IRQL
  • 互鎖操作
  • 無鎖單鏈表
  • 自旋鎖(忙等待)

另一類是PASSIVE_LEVEL上的線程之間的同步。Windows定義了統一的機制來支持各種線程同步原語:分發器對象(dispatcher object),其數據結構頭部爲DISPATCH_HEADER。Windows Server 2003實現了以下分發器對象:

  • 事件
  • 突變體
  • 信號量
  • 隊列對象
  • 進程對象
  • 程對象
  • 定時器對象
  • 門對象
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章