轉:http://mp.weixin.qq.com/s?__biz=MzA3NDcyMTQyNQ==&mid=400583492&idx=1&sn=3b18c463dcc45103b76a3419ceabe84c&scene=2&srcid=1213Z5CBO8W4jCmTSFI74uIb&from=timeline&isappinstalled=0#wechat_redirecthtml
Linux kernel 成功的兩個緣由:node
靈活的架構設計使得大量的志願開發者可以很容易加入到開發過程當中;linux
每一個子系統(尤爲是那些須要改進的)都具有良好的可擴展性。程序員
正是這兩個緣由使得Linux kernel能夠不斷進化和改進。算法
Fig 1 - 計算機系統分層結構編程
分層結構的原則:安全
the dependencies between subsystems are from the top down: layers pictured near the top depend on lower layers, but subsystems nearer the bottom do not depend on higher layers.網絡
這種子系統之間的依賴性只能是從上到下,也就是圖中頂部的子系統依賴底部的子系統,反之則不行。數據結構
虛擬化(抽象),將計算機硬件抽象爲一臺虛擬機,供用戶架構
進程process使用;進程運行時徹底不須要知道硬件是如何工做的,只要調用 Linux kernel 提供的
虛擬接口virtual interface便可。
多任務處理,其實是多個任務在並行使用計算機硬件資源,內核的任務是仲裁對資源的使用,製造每一個進程都覺得本身是獨佔系統的錯覺。
PS:進程上下文切換就是要換掉程序狀態字、換掉頁表基地址寄存器的內容、換掉 current 指向的 task_struct 實例、換掉 PC ——>也就換掉了進程打開的文件(經過 task_struct 的 files 能夠找到)、換掉了進程內存的執行空間(經過 task_struct 的 mem 能夠找到);
Linux內核的總體架構
中心繫統是進程調度器Process Scheduler,SCHED:全部其他的子系統都依賴於進程調度器,由於其他子系統都須要阻塞和恢復進程。當一個進程須要等待一個硬件動做完成時,相應子系統會阻塞這個進程;當這個硬件動做完成時,子系統會將這個進程恢復:這個阻塞和恢復動做都要依賴於進程調度器完成。
上圖中的每個依賴箭頭都有緣由:
進程調度器依賴
內存管理器Memory manager:進程恢復執行時,須要依靠內存管理器分配供它運行的內存。
IPC 子系統依賴於內存管理器:共享內存機制是進程間通訊的一種方法,運行兩個進程利用同一塊共享的內存空間進行信息傳遞。
VFS 依賴於
網絡接口Network Interface:支持 NFS 網絡文件系統;
VFS 依賴於內存管理器:支持 ramdisk 設備
內存管理器依賴於 VFS,由於要支持
交換swapping,能夠將暫時不運行的進程換出到磁盤上的
交換分區swap,進入掛起狀態。
只有極少數的程序員須要橫跨多個模塊開展工做,這種狀況確實會發生,僅發生在當前系統須要依賴另外一個子系統時;
、
文件系統模塊logical filesystem modules、
網絡設備驅動network device drivers和
網絡協議模塊network protocol modules這四個模塊的可擴展性最高。
進程調度器針對每一個進程維護一個數據結構 task_struct;全部的進程用鏈表管理,造成 task list;進程調度器還維護一個 current 指針指向當前正在佔用 CPU 的進程。
內存管理器存儲每一個進程的虛擬地址到物理地址的映射;而且也提供瞭如何換出特定的頁,或者是如何進行缺頁處理。這些信息存放在數據結構 mm_struct 中。每一個進程都有一個 mm_struct 結構,在進程的 task_struct 結構中有一個指針 mm 指向次進程的 mm_struct 結構。
在 mm_struct 中有一個指針 pgd,指向該進程的頁目錄表(即存放頁目錄首地址)——>當該進程被調度時,此指針被換成物理地址,寫入控制寄存器 CR3(x86體系結構下的頁基址寄存器)
I-nodes
VFS 經過 inodes 節點表示磁盤上的文件鏡像,inodes 用於記錄文件的物理屬性。每一個進程都有一個 files_struct 結構,用於表示該進程打開的文件,在 task_struct 中有個 files 指針。使用 inodes 節點能夠實現文件共享。文件共享有兩種方式:(1)經過同一個系統打開文件 file 指向同一個 inodes 節點,這種狀況發生於父子進程間;(2)經過不一樣系統打開文件指向同一個 inode 節點,舉例有硬連接;或者是兩個不相關的指針打開同一個文件。
內核中全部的數據結構的根都在進程調度器維護的任務列表鏈表中。系統中每一個進程的的數據結構 task_struct 中有一個指針 mm 指向它的內存映射信息;也有一個指針 files 指向它打開的文件(用戶打開文件表);還有一個指針指向該進程打開的網絡套接字。
進程調度器是 Linux kernel 中最重要的子系統。系統經過它來控制對 CPU 的訪問——不只僅是用戶進程對 CPU 的訪問,也包括其他子系統對 CPU 的訪問。
進程調度器
調度策略模塊scheduling policy module:決定哪一個進程得到對 CPU 的訪問權;調度策略應該讓全部進程儘量公平得共享 CPU。
設計一組統一的抽象接口來屏蔽特定體系接口芯片的硬件細節。這個模塊與 CPU 交互以阻塞和恢復進程。這些操做包括獲取每一個進程須要保存的寄存器和狀態信息、執行彙編代碼來完成阻塞或者恢復操做。
與調度策略模塊交互將決定下一個執行的進程,而後調用體系結構相關的代碼去恢復那個進程的執行。不只如此,這個模塊還會調用內存管理器的接口來確保被阻塞的進程的內存映射信息被正確得保存起來。
容許用戶進程訪問 Linux Kernel 明確暴露給用戶進程的資源。經過一組定義合適的基本上不變的接口(POSIX 標準),將用戶應用程序和 Linux 內核解耦,使得用戶進程不會受到內核變化的影響。
調度器維護一個數據結構——task list,其中的元素時每一個活動的進程 task_struct 實例;這個數據結構不只僅包含用來阻塞和恢復進程的信息,也包含額外的計數和狀態信息。這個數據結構在整個 kernel 層均可以公共訪問。
正如前面提到過的,調度器須要調用內存管理器提供的功能,去爲須要恢復執行的進程選擇合適的物理地址,正由於如此,因此 進程調度器子系統依賴於內存管理子系統。當其餘內核子系統須要等待硬件請求完成時,它們都依賴於進程調度子系統進行進程的阻塞和恢復。這種依賴性經過函數調用和訪問共享的 task list 數據結構來體現。全部的內核子系統都要讀或者寫表明當前正在運行進程的數據結構,所以造成了貫穿整個系統的雙向數據流。
除了內核層的數據流和控制流,OS 服務層還給用戶進程提供註冊定時器的接口。這造成了由調度器對用戶進程的控制流。一般喚醒睡眠進程的用例不在正常的控制流範圍,由於用戶進程沒法預知什麼時候被喚醒。最後,調度器與 CPU 交互來阻塞和恢復進程,這又造成它們之間的數據流和控制流——CPU 負責打斷當前正在運行的進程,並容許內核調度其餘的進程運行。
內存管理模塊負責控制進程如何訪問物理內存資源。經過硬件內存管理系統(MMU)管理進程虛擬內存和機器物理內存之間的映射。每個進程都有本身獨立的虛擬內存空間,因此兩個進程可能有相同的虛擬地址,可是它們實際上在不一樣的物理內存區域運行。MMU 提供內存保護,讓兩個進程的物理內存空間不互相干擾。內存管理模塊還支持交換——將暫時不用的內存頁換出到磁盤上的交換分區,這種技術讓進程的虛擬地址空間大於物理內存的大小。虛擬地址空間的大小由機器字長決定。
內存管理子系統
架構相關模塊architecture specific module提供訪問物理內存的虛擬接口;
架構無關模塊architecture independent module負責每一個進程的地址映射以及虛擬內存交換。當發生缺頁錯誤時,由該模塊負責決定哪一個內存頁應該被換出內存——由於這個內存頁換出選擇算法幾乎不須要改動,因此這裏沒有創建一個獨立的策略模塊。
系統調用接口system call interface爲用戶進程提供嚴格的訪問接口(malloc 和 free;mmap 和 ummap)。這個模塊容許用進程分配和釋放內存、執行內存映射文件操做。
內存管理存放每一個進程的虛擬內存到物理內存的映射信息。這種映射信息存放在 mm_struct 結構實例中,這個實例的指針又存放在每一個進程的 task_struct 中。除了存放映射信息,數據塊中還應該存放關於內存管理器如何獲取和存儲頁的信息。例如:可執行代碼可以將可執行鏡像做爲備份存儲;可是動態申請的數據則必須備份到系統頁中。(這個沒看懂,請高手解惑?)
最後,內存管理模塊還應該存放訪問和技術信息,以保證系統的安全。
內存管理器控制物理內存,當頁面失敗page fault發生時,接受硬件的通知(缺頁中斷)—— 這意味着在內存管理模塊和內存管理硬件之間存在雙向的數據流和控制流。內存管理也依賴文件系統來支持交換和內存映射 I/O——這種需求意味着內存管理器須要調用對文件系統提供的函數接口procedure calls,往磁盤中存放內存頁和從磁盤中取內存頁。由於文件系統請求很是慢,因此在等待內存頁被換入以前,內存管理器要讓進程須要進入休眠——這種需求讓內存管理器調用進程調度器的接口。因爲每一個進程的內存映射存放在進程調度器的數據結構中,因此在內存管理器和進程調度器之間也有雙向的數據流和控制流。用戶進程能夠創建新的進程地址空間,而且可以感知缺頁錯誤——這裏須要來自內存管理器的控制流。通常來講沒有用戶進程到內存管理器的數據流,可是用戶進程卻能夠經過 select 系統調用,從內存管理器獲取一些信息。
虛擬文件系統爲存儲在硬件設備上數據提供統一的訪問接口。能夠兼容不一樣的文件系統(ext2,ext4,ntf等等)。計算機中幾乎全部的硬件設備都被表示爲一個通用的設備驅動接口。邏輯文件系統促進與其餘操做系統標準的兼容性,而且容許開發者以不一樣的策略實現文件系統。虛擬文件系統更進一步,容許系統管理員在任何設備上掛載任何邏輯文件系統。虛擬文件系統封裝物理設備和邏輯文件系統的細節,而且容許用戶進程使用統一的接口訪問文件。
除了傳統的文件系統目標,VFS 也負責裝載新的可執行文件。這個任務由邏輯文件系統模塊完成,使得 Linux 能夠支持多種可執行文件。
虛擬文件系統模塊
:提供全部設備的同一視圖
:針對每種支持的文件系統
提供硬件資源和邏輯文件系統都無關的接口,這個模塊經過塊設備節點或者字符設備節點提供全部的資源。
提供用戶進程對文件系統的統一控制訪問。虛擬文件系統爲用戶進程屏蔽了全部特殊的特性。
全部文件使用 inode 表示。每一個 inode 都記錄一個文件在硬件設備上的位置信息。不只如此,inode 還存放着指向邏輯文件系統模塊和設備驅動的的函數指針,這些指針可以執行具體的讀寫操做。經過按照這種形式(就是面向對象中的虛函數的思想)存放函數指針,具體的邏輯文件系統和設備驅動能夠向內核註冊本身而不須要內核依賴具體的模塊特性。
一個特殊的設備驅動是 ramdisk,這個設備在主存中開闢一片區域,並把它當成持久性存儲設備使用。這個設備驅動使用內存管理模塊完成任務,因此在 VFS 與對內存管理模塊存在依賴關係(圖中的依賴關係反了,應該是 VFS 依賴於內存管理模塊)、數據流和控制流。
邏輯文件系統支持網絡文件系統。這個文件系統像訪問本地文件同樣,從另外一臺機器上訪問文件。爲了實現這個功能,一種邏輯文件系統經過網絡子系統完成它的任務——這引入了 VFS 對網絡子系統的一個依賴關係以及它們之間的控制流和數據流。
正如前面提到的,內存管理器使用 VFS 完成內存交換功能和內存映射 I/O。另外,當 VFS 等待硬件請求完成時,VFS 須要使用進程調度器阻塞進程;當請求完成時,VFS 須要經過進程調度器喚醒進程。最後,系統調用接口容許用戶進程調用來存取數據。不像前面的子系統,VFS 沒有提供給用戶註冊不明確調用的機制,因此沒有從VFS到用戶進程的控制流。
網絡子系統讓 Linux 系統可以經過網絡與其餘系統相連。這個子系統支持不少硬件設備,也支持不少網絡協議。網絡子系統將硬件和協議的實現細節都屏蔽掉,並抽象出簡單易用的接口供用戶進程和其餘子系統使用——用戶進程和其他子系統不須要知道硬件設備和協議的細節。
網絡協議層模塊圖
提供全部硬件設備的一致訪問接口,使得高層子系統不須要知道硬件的細節信息。
負責實現每個網絡傳輸協議,例如:TCP,UDP,IP,HTTP,ARP等等~
提供獨立於具體協議和具體硬件設備的一致性接口。這使得其他內核子系統無需依賴特定的協議或者設備就能訪問網絡。
規定了用戶進程能夠訪問的網絡編程API
每一個網絡對象都被表示爲一個套接字socket。套接字與進程關聯的方法和 inode 節點相同。經過兩個 task_struct 指向同一個套接字,套接字能夠被多個進程共享。
當網絡子系統須要等待硬件請求完成時,它須要經過進程調度系統將進程阻塞和喚醒——這造成了網絡子系統和進程調度子系統之間的控制流和數據流。不只如此,虛擬文件系統經過網絡子系統實現網絡文件系統(NFS)——這造成了 VFS 和網絡子系統指甲的數據流和控制流。
一、Linux 內核是整個 Linux 系統中的一層。內核從概念上由五個主要的子系統構成:進程調度器模塊、內存管理模塊、虛擬文件系統、網絡接口模塊和進程間通訊模塊。這些模塊之間經過函數調用和共享數據結構進行數據交互。
二、Linux 內核架構促進了他的成功,這種架構使得大量的志願開發人員能夠合適得分工合做,而且使得各個特定的模塊便於擴展。
可擴展性一:Linux 架構經過一項數據抽象技術使得這些子系統成爲可擴展的——每一個具體的硬件設備驅動都實現爲單獨的模塊,該模塊支持內核提供的統一的接口。經過這種方式,我的開發者只須要和其餘內核開發者作最少的交互,就能夠爲 Linux 內核添加新的設備驅動。
可擴展性二:Linux 內核支持多種不一樣的體系結構。在每一個子系統中,都將體系結構相關的代碼分割出來,造成單獨的模塊。經過這種方法,一些廠家在推出他們本身的芯片時,他們的內核開發小組只須要從新實現內核中機器相關的代碼,就能夠講內核移植到新的芯片上運行。
參考文章:
http://oss.org.cn/ossdocs/linux/kernel/a1/index.html
http://www.cs.cmu.edu/afs/cs/project/able/www/paper_abstracts/intro_softarch.html
http://www.cs.cmu.edu/afs/cs/project/able/www/paper_abstracts/intro_softarch.html
http://www.fceia.unr.edu.ar/ingsoft/monroe00.pdf
內核源碼:http://lxr.oss.org.cn/
來源:簡書 參考原文:http://oss.org.cn/ossdocs/linux/kernel/a1/index.html 做者: Ivan Bowman
編譯文章:http://www.jianshu.com/p/c5ae8f061cfe 譯者: 杜琪