代碼中自由顏如玉!代碼中自有黃金屋!那么Linux內(nèi)核代碼到底有多少行?
我們需要多久能讀完呢?
一、內(nèi)核行數(shù)
Linux內(nèi)核分為CPU調(diào)度、內(nèi)存管理、網(wǎng)絡(luò)和存儲(chǔ)四大子系統(tǒng),針對(duì)硬件的驅(qū)動(dòng)成百上千。代碼的數(shù)量更是大的驚人。
先說說最早的內(nèi)核linux 0.11,這本書《Linux內(nèi)核完全剖析》可以說很多驅(qū)動(dòng)工程師都學(xué)習(xí)過,我花了大概1個(gè)半月,勉強(qiáng)看了一遍。
再來看看內(nèi)核代碼量的統(tǒng)計(jì)。
2020年1月1日,Linux內(nèi)核Git源碼樹中的代碼達(dá)到了2780萬行。
phoronix網(wǎng)站統(tǒng)計(jì)了Linux內(nèi)核在進(jìn)入2020年時(shí)的一些源碼數(shù)據(jù)并作了總結(jié)。
從統(tǒng)計(jì)數(shù)據(jù)來看,Linux內(nèi)核源碼樹共有:
27852148行(包括文檔、Kconfig文件、樹中的用戶空間實(shí)用程序等)、
887925次commit
21074位不同的作者
2780萬行代碼分布在66492個(gè)文件中。
Linux內(nèi)核從最初的10000行代碼到現(xiàn)在的2780萬行代碼就是全球精英共同貢獻(xiàn)的結(jié)果。
按照一天一萬行的速度,也需要2700天,也需要7年多。
這還是建立在所有單次都認(rèn)識(shí),所有代碼邏輯看了的都懂,而且都不忘記的基礎(chǔ)上。
實(shí)際上即使我們真的看完了,幾年后內(nèi)核又會(huì)有非常大的變化,可以說一輩子都看不完Linux內(nèi)核的代碼。
Linux內(nèi)核Git源碼樹中的代碼達(dá)到了2780萬行,核心代碼只有2%是由李納斯?托瓦茲自己編寫的,其他均是其他個(gè)人和組織貢獻(xiàn)的,李納斯?托瓦茲公開了Linux但保留了選擇新代碼和需要合并的新方法的最終裁定權(quán)。
除了Linus Torvalds,對(duì)內(nèi)核貢獻(xiàn)最多的是David S.Miller、 Mark Brown、Takashi Iwai、Arnd Bergmann、Al Viro和Mauro Carvalho Chehab。
而參與貢獻(xiàn)的公司,從域名統(tǒng)計(jì)來看,谷歌、Intel與Red Hat排在了最前列。
二、內(nèi)核目錄文件大小
然而,現(xiàn)在的內(nèi)核已經(jīng)膨脹的不成樣子了,以還不算最新的linux-4.1.15為例:
整個(gè)內(nèi)核源碼一共約 793M:
驅(qū)動(dòng)代碼占了大概一半,大約380M:
體系相關(guān)的代碼大約134M:
網(wǎng)路子系統(tǒng)相關(guān)的代碼26M:
文件系統(tǒng)相關(guān)的代碼37M:
linux內(nèi)核核心代碼大約6.8M:
這些目錄任意一個(gè)目錄想完全看明白都非常不容易。
三、內(nèi)核子系統(tǒng)
什么是內(nèi)核:
在計(jì)算機(jī)科學(xué)中是一個(gè)用來管理軟件發(fā)出的數(shù)據(jù)I/O(輸入與輸出)要求的計(jì)算機(jī)程序,將這些要求轉(zhuǎn)譯為數(shù)據(jù)處理的指令并交由中央處理器(CPU)及計(jì)算機(jī)中其他電子組件進(jìn)行處理,是現(xiàn)代操作系統(tǒng)中最基本的部分。
它是為眾多應(yīng)用程序提供對(duì)計(jì)算機(jī)硬件的安全訪問的一部分軟件,這種訪問是有限的,并由內(nèi)核決定一個(gè)程序在什么時(shí)候?qū)δ巢糠钟布僮鞫嚅L(zhǎng)時(shí)間。
linux內(nèi)核代碼涉及知識(shí)點(diǎn)包括匯編指令、c語言、硬件組成原理、操作系統(tǒng)、數(shù)據(jù)結(jié)構(gòu)和算法、各種外設(shè)總線、驅(qū)動(dòng)、網(wǎng)絡(luò)協(xié)議棧。
直接對(duì)硬件操作是非常復(fù)雜的。所以內(nèi)核通常提供一種硬件抽象的方法,來完成這些操作。
通過進(jìn)程間通信機(jī)制及系統(tǒng)調(diào)用,應(yīng)用進(jìn)程可間接控制所需的硬件資源(特別是處理器及IO設(shè)備)。
最上面是用戶(或應(yīng)用程序)空間。這是用戶應(yīng)用程序執(zhí)行的地方。用戶空間之下是內(nèi)核空間,Linux 內(nèi)核正是位于這里。
GNU C Library (glibc)也在這里。它提供了連接內(nèi)核的系統(tǒng)調(diào)用接口,還提供了在用戶空間應(yīng)用程序和內(nèi)核之間進(jìn)行轉(zhuǎn)換的機(jī)制。
內(nèi)核和用戶空間的應(yīng)用程序使用的是不同的保護(hù)地址空間。
每個(gè)用戶空間的進(jìn)程都使用自己的虛擬地址空間,而內(nèi)核則占用單獨(dú)的地址空間。
Linux 內(nèi)核可以進(jìn)一步劃分成 3 層。最上面是系統(tǒng)調(diào)用接口,它實(shí)現(xiàn)了一些基本的功能,例如 read 和 write。
系統(tǒng)調(diào)用接口之下是內(nèi)核代碼,可以更精確地定義為獨(dú)立于體系結(jié)構(gòu)的內(nèi)核代碼。這些代碼是 Linux 所支持的所有處理器體系結(jié)構(gòu)所通用的。
在這些代碼之下是依賴于體系結(jié)構(gòu)的代碼,構(gòu)成了通常稱為 BSP(Board Support Package)的部分。這些代碼用作給定體系結(jié)構(gòu)的處理器和特定于平臺(tái)的代碼。
內(nèi)核主要系統(tǒng)包括:SCI:系統(tǒng)調(diào)用接口
PM:進(jìn)程管理
VFS:虛擬文件系統(tǒng)
MM:內(nèi)存管理
Network Stack:內(nèi)核協(xié)議棧
Arch:體系架構(gòu)
DD:設(shè)備驅(qū)動(dòng)
1 系統(tǒng)調(diào)用接口
SCI 層提供了某些機(jī)制執(zhí)行從用戶空間到內(nèi)核的函數(shù)調(diào)用。這個(gè)接口依賴于體系結(jié)構(gòu),甚至在相同的處理器家族內(nèi)也是如此。
SCI 實(shí)際上是一個(gè)非常有用的函數(shù)調(diào)用多路復(fù)用和多路分解服務(wù)。
在 ./linux/kernel 中您可以找到 SCI 的實(shí)現(xiàn),并在 ./linux/arch 中找到依賴于體系結(jié)構(gòu)的部分。
2 進(jìn)程管理
進(jìn)程管理的重點(diǎn)是進(jìn)程的執(zhí)行。
在內(nèi)核中,這些進(jìn)程稱為線程,代表了單獨(dú)的處理器虛擬化(線程代碼、數(shù)據(jù)、堆棧和 CPU 寄存器)。
在用戶空間,通常使用進(jìn)程 這個(gè)術(shù)語,不過 Linux 實(shí)現(xiàn)并沒有區(qū)分這兩個(gè)概念(進(jìn)程和線程)。
內(nèi)核通過 SCI 提供了一個(gè)應(yīng)用程序編程接口(API)來創(chuàng)建一個(gè)新進(jìn)程(fork、exec 或 Portable Operating System Interface [POSIX] 函數(shù)),停止進(jìn)程(kill、exit),并在它們之間進(jìn)行通信和同步(signal 或者 POSIX 機(jī)制)。
3 內(nèi)存管理
內(nèi)核所管理的另外一個(gè)重要資源是內(nèi)存。為了提高效率,如果由硬件管理虛擬內(nèi)存,內(nèi)存是按照所謂的內(nèi)存頁方式進(jìn)行管理的(對(duì)于大部分體系結(jié)構(gòu)來說都是 4KB)。
Linux 包括了管理可用內(nèi)存的方式,以及物理和虛擬映射所使用的硬件機(jī)制。
4 虛擬文件系統(tǒng)
虛擬文件系統(tǒng)(VFS)是 Linux 內(nèi)核中非常有用的一個(gè)方面,因?yàn)樗鼮槲募到y(tǒng)提供了一個(gè)通用的接口抽象。VFS 在 SCI 和內(nèi)核所支持的文件系統(tǒng)之間提供了一個(gè)交換層。
在 VFS 上面,是對(duì)諸如 open、close、read 和 write 之類的函數(shù)的一個(gè)通用 API 抽象。在 VFS 下面是文件系統(tǒng)抽象,它定義了上層函數(shù)的實(shí)現(xiàn)方式。
它們是給定文件系統(tǒng)(超過 50 個(gè))的插件。文件系統(tǒng)的源代碼可以在 ./linux/fs 中找到。
文件系統(tǒng)層之下是緩沖區(qū)緩存,它為文件系統(tǒng)層提供了一個(gè)通用函數(shù)集(與具體文件系統(tǒng)無關(guān))。
這個(gè)緩存層通過將數(shù)據(jù)保留一段時(shí)間(或者隨即預(yù)先讀取數(shù)據(jù)以便在需要是就可用)優(yōu)化了對(duì)物理設(shè)備的訪問。緩沖區(qū)緩存之下是設(shè)備驅(qū)動(dòng)程序,它實(shí)現(xiàn)了特定物理設(shè)備的接口。
5 網(wǎng)絡(luò)堆棧
網(wǎng)絡(luò)堆棧在設(shè)計(jì)上遵循模擬協(xié)議本身的分層體系結(jié)構(gòu)。
回想一下,Internet Protocol (IP) 是傳輸協(xié)議(通常稱為傳輸控制協(xié)議或 TCP)下面的核心網(wǎng)絡(luò)層協(xié)議。TCP 上面是 socket 層,它是通過 SCI 進(jìn)行調(diào)用的。
socket 層是網(wǎng)絡(luò)子系統(tǒng)的標(biāo)準(zhǔn) API,它為各種網(wǎng)絡(luò)協(xié)議提供了一個(gè)用戶接口。
從原始幀訪問到 IP 協(xié)議數(shù)據(jù)單元(PDU),再到 TCP 和 User Datagram Protocol (UDP),socket 層提供了一種標(biāo)準(zhǔn)化的方法來管理連接,并在各個(gè)終點(diǎn)之間移動(dòng)數(shù)據(jù)。內(nèi)核中網(wǎng)絡(luò)源代碼可以在 ./linux/net 中找到。
6 設(shè)備驅(qū)動(dòng)程序
Linux 內(nèi)核中有大量代碼都在設(shè)備驅(qū)動(dòng)程序中,它們能夠運(yùn)轉(zhuǎn)特定的硬件設(shè)備。
Linux 源碼樹提供了一個(gè)驅(qū)動(dòng)程序子目錄,這個(gè)目錄又進(jìn)一步劃分為各種支持設(shè)備,例如 Bluetooth、I2C、serial 等。設(shè)備驅(qū)動(dòng)程序的代碼可以在 ./linux/drivers 中找到。
下面這個(gè)圖形象的講解了Linux內(nèi)核都有哪些東西!
四、如何學(xué)習(xí)內(nèi)核?
1. 學(xué)習(xí)主線
linux內(nèi)核源碼大而全,一個(gè)人,即使再聰明、再有精力,也不可能完全看完、看懂所有的linux內(nèi)核源碼。
一口君建議按照以下主線進(jìn)行深入研究:
-
- linux驅(qū)動(dòng)架構(gòu)linux網(wǎng)絡(luò)子系統(tǒng)
-
-
- linux內(nèi)核啟動(dòng)過程
-
linux內(nèi)存管理機(jī)制linux調(diào)度器linux進(jìn)程管理linux虛擬機(jī)制(kvm)linux內(nèi)核實(shí)時(shí)化技術(shù)
沿著某一個(gè)主線,深入進(jìn)去,在研究清楚這個(gè)主線的同時(shí),向其他的主線擴(kuò)展、滲透和學(xué)習(xí)。
此處之所以將驅(qū)動(dòng)列為學(xué)習(xí)內(nèi)核的入口,是因?yàn)閮?nèi)核為很多外設(shè)驅(qū)動(dòng)實(shí)現(xiàn)了架構(gòu),
比如I2C、SPI、UART、PCIE、字符設(shè)備、網(wǎng)絡(luò)設(shè)備、塊設(shè)備,
我們可以從最基本的字符設(shè)備學(xué)起,
學(xué)習(xí)如何編寫一個(gè)簡(jiǎn)單的模塊
學(xué)習(xí)如何如何為一些簡(jiǎn)單的設(shè)備比如LED、KEY、ADC等編寫驅(qū)動(dòng)
可以說驅(qū)動(dòng)是我們學(xué)習(xí)內(nèi)核最簡(jiǎn)單的入口,
由點(diǎn)到線、由線到面、由面到體,層層深入、不斷精進(jìn),是學(xué)習(xí)linux內(nèi)核源碼的一個(gè)有效的方法。
2. 代碼閱讀工具
對(duì)于代碼閱讀方法從兩個(gè)角度來介紹,一個(gè)方面是需要選擇一個(gè)比較有效閱讀代碼的工具。
一口君強(qiáng)烈推薦:source insight這款閱讀代碼神器!
也可以使用vscode或者vim+ctags的組合。
不過一口君十幾年的從業(yè)經(jīng)驗(yàn),99%以上的開發(fā)人員都選擇SI閱讀內(nèi)核代碼。
代碼并不是寫給人看的,而是交給機(jī)器運(yùn)行的。
所以我們?nèi)ダ斫鈩e人的代碼時(shí),并不能像看小說一樣去通篇的閱讀代碼,而應(yīng)該是像研究化石一樣去調(diào)查它,解密它。
有時(shí)我們往往也需要把對(duì)方的一段代碼親手的實(shí)現(xiàn)一遍,然后自己舉一反三看自己會(huì)怎么去實(shí)現(xiàn)它,才能真正的理解。
3. 學(xué)習(xí)的內(nèi)核版本
有些人推薦先閱讀一些低版本的內(nèi)核,比如0.01版的,總代碼量才1萬行左右。
閱讀這個(gè)代碼大概一個(gè)月應(yīng)該能比較清晰了。
但是,改代碼與現(xiàn)在的代碼差異巨大,閱讀后可以理解基本思想,但對(duì)理解現(xiàn)有代碼的幫助不是特別明顯。
3.10版本之后的內(nèi)核都支持設(shè)備樹!
所以一口君建議是盡量選擇3.10版本之后的代碼閱讀學(xué)習(xí)。
最好選擇一款開發(fā)板學(xué)習(xí)!
開發(fā)板的選擇一定要選擇資料比較全,售后比較好的品牌!
否則學(xué)習(xí)中遇到的一個(gè)小問題都可能被卡個(gè)一兩周。
無形中增加了學(xué)習(xí)的成本,要知道時(shí)間就是金錢!對(duì)于初學(xué)者來說,強(qiáng)烈推薦正點(diǎn)原子的開發(fā)板!
4. 學(xué)習(xí)Linux最重要的是培養(yǎng)自己寫代碼的能力和對(duì)Linux框架結(jié)構(gòu)的了解
Linux內(nèi)核中絕大部分代碼都是由這個(gè)地球上頂尖的技術(shù)大牛所編寫,這些代碼的高內(nèi)聚低耦合,其精準(zhǔn)度,簡(jiǎn)潔度、質(zhì)量都相當(dāng)?shù)母?,每每看到一段高質(zhì)量的代碼,一口君都會(huì)被那一行行枯燥的代碼背后隱藏的設(shè)計(jì)思想所震撼,所折服!
閱讀內(nèi)核的代碼簡(jiǎn)直就是在欣賞藝術(shù)品!
很多粉絲問我如何提高自己的C語言編程水平,一口君不厭其煩的 重復(fù)著同樣一句話:看Linux內(nèi)核!
代碼中自由顏如玉!代碼中自有黃金屋!我們一定要像泡妞一樣來泡內(nèi)核!時(shí)刻保持激情,任性和耐性!
耐住寂寞,天天讀它,泡她!從量變到質(zhì)變!水滴石穿!
愿各位都能夠熟練掌握Linux,實(shí)現(xiàn)從程序員涅槃成為真正的軟件大師!