內核這麼堅硬,當初你是怎麼一步步達到現在市面上的要求的,其中應該有些血淚吧。


步入殿堂,我的理解就是自己能靠這手藝養活自己,不僅餓不死,還有碗飽飯吃。對於資質平平的普通人來說,這也不難,就是堅持和時間的問題。大家看到的高手都是聰明人,他們不做內核開發做其他工作也會是很牛X,我們這些普通人之所以說要堅持和時間,是因為我們不管做什麼事情,能有口飽飯吃都得靠堅持和時間。

內核開發也是寫軟體代碼,和其他的軟體代碼開發工作沒啥區別:創造有人用的代碼。這就是一份工作,把工作做好,領薪水買米面油氣交房前。可能不同的是內核軟體沒有用戶界面,普通用戶沒法直接看到效果。

這份工作的好處是穩定和靈活,因為市場上工作崗位數量遠遠超過從事內核開發的聰明人,所以普通人如果能夠達到基本的工作要求,也可以得到一份穩定而且靈活的工作。

穩定是指,薪水比較穩定,崗位也比較穩定,不會出現短期內快速加薪升職的情況。靈活是指,有很多此類崗位是可以提供遠程辦公的,所以如果不強求留在北上廣深,而是回到老家和家裡人一起生活,找一個彼此相愛的人廝守,這份薪水可以在當地過上嬌縱淫慾的生活妥妥沒問題。此外,只要能完成工作,時間都是自己安排的。如果真想做內核開發(其實絕大多數人並不感興趣),這種氛圍還是很有助於能力的成長的。

聰明人的例子就不說了,扎心。大家分享一下我自己這個普通人是如何走上做內核開發這條路,還至今沒有餓死的。

我是97年上的大學,學校比較一般,剛入學的時候我滿腦子想的是如何畢業之後和老家親戚們一起經營農村土特產。大概是大二下學期有一次在圖書館看書,無意中看到了一本介紹Linux的薄書,作者寫的很有意思,我居然就在圖書館一直看到很晚把那本書給看完了。然後我就決定,要去找Linux來玩玩。當時學校的機房裡還沒有Linux,我自己也沒有電腦,只能是殘念了。後來大三暑假我去了一家叫美商網虎的Linux公司實習,算是真正接觸了這個系統,感覺很酷。關鍵是編程也是黑屏幕和我學DOS編程的環境很像,上手很順利,呵呵。再後來就是在沈樹鏞教授指導下,在學校計算中心開課跟大家介紹這個系統的使用,自己也利用計算中心的網路環境和設備環境,很深入的了解了這個系統的使用和配置,以及基本的編程概念。

然後就開始進去了學習Linux內核編程的大坑,哈哈,什麼不懂學什麼,一轉眼就十幾年過去了。從驅動開始做起,然後做應用,然後做系統管理工具,然後做文件系統,然後去互聯網公司做了幾年工程管理,現在又回到一線崗位繼續做Linux內核開發。

一眨眼,從我98年第一次知道Linux到現在,已經20年過去了。現在還能依然靠開發Linux內核養家糊口,還把自己吃成了胖子,我覺得已經蠻開心了。如果把這種狀態稱之為步入殿堂的哈,可能最重要的一條就是不要放棄自己。Linux內核代碼是由一群優秀的工程師開發的,裡面還會嘗嘗夾雜很多其它領域專業知識。普通開發者(譬如我)看不懂或者需要學習其它知識是家常便飯,時時會覺得自己和其他開發者比起來簡直就是一頭蠢豬,做這一行完全不適合沒出路。這種感覺會經常冒出來 然而,對於系統軟體開發的喜愛是由心而生的,隨著越來越深入,我也么逐漸接受了自己沒有預期那麼優秀的現實,並鼓勵自己蠢也不妨礙我喜歡這個技術

做Linux內核開發和其他軟體開發差別不太大,要做到優秀都是要付出努力的,沒什麼高低之分。這畢竟只是一份工作,要認真對待,但它也不是生活的全部。作為一個工程師,一個中國人,如果通過參與這個技術,從很具體的細節做起,讓生活更美好,讓世界更美好,讓我們彼此之間更和諧,這是很有樂趣的事情,也是我認識的很多比我優秀的多的內核開發者們發自內心的動力。

上圖右一胖子是本人。

系統軟體開發,坦誠說並不適合絕大多數人,但如果有緣能夠參與其中,養家糊口沒問題的。如果有朋友覺得好難,或者好苦,只要你還喜歡就不要放棄。你不孤單,還有很多「蠢貨」和你一樣,一邊撓頭苦逼,一邊傻樂傻笑


內核沒有什麼殿堂,也並不高大上。相反的, 我更多的時候看到的是搞內核的人視野很狹窄,技術很單調,跳出內核什麼都不懂。

偽內核高手的典型特徵是:

1 不懂用戶態。(是的, 不懂用戶態的人本質上也不懂內核)

2 只會C這種最基礎最初級的語言,拒絕學習其它OO語言。殊不知,內核雖然是C,但是也處處在採用OO 的寫法。學習下高級語言拓展思維非常必要。

3 認為Linux是優雅的設計和實現。其實並不是,Linux的糟粕跟所謂的精華一樣多。比如Linux的進線程設計是很模糊的,一點都不清晰。但其它平台則劃分的更清晰更自然。再比如Windows的結構化異常處理,可以說是一大創舉,Linux黨沒幾個人懂。內核里最複雜的部分, 早就不是什麼內存管理,進程調度了。其實GUI才是最複雜最有挑戰的,Linux在這個領域跟win和mac 完全沒有可比性。mac os 雖然開源,但是你看他捨得公開gui部分嗎?

4 從代碼層面講,Linux的代碼也很垃圾。我認為Linux內核連最起碼的命名都沒有做好。比如 local_irq_save , 真的是 save 嗎 ? 其實應該是 local_irq_disable_and_saveget_cpu 單看這函數名,你能想到其實是個關閉搶佔? 同樣的函數名,到了kvm里又是另一個含義。在用戶態,發信號的函數起名叫 kill, 要殺人還是咋地? 整數除0 會報錯成 float point 異常。呵呵。

那麼想成為真正的Linux內核高手應該怎麼做呢 ?

1 學習體系結構。保護模式都幾十年了,很多人對基本的運行環境切換,頁表管理,內存分頁分段,系統調用都搞不清楚。Intel 手冊第三卷 system programming guide 不敢說通讀,至少關鍵問題需要完整看一遍。不然連個自旋鎖原理都搞不清楚。

2 學習編譯原理。我這裡說的編譯原理,不是常規的前端詞法分析,語法分析,語義分析,語法樹生成。其實更主要的是後端。後端才是銜接操作系統的部分。指令選擇,指令調度,寄存器分配跟前面說的體系結構關聯緊密,相輔相成,可以互相促進理解。另外,編譯跟裝載又是一起的,而程序的裝載又是跟進線程的初始化,內存管理緊密相關的。只有把這部分徹底融會貫通才算打通任督二脈。發明UNIX操作系統的兩位老先生,你當人家只會搞內核?Ritchie發明了C語言,還寫過編輯器。編譯器前端離不開的狀態機構造技術,Thompson構造法就是Thompson發明的,人家現在還在搞go 語言。從根本上講,軟體做的事情90%以上都是形式轉化,而編譯器融合了形式轉化的大部分精華。錯過編譯器技術的人都不知道自己錯過了什麼。

3 debug,解決難題。Linux內核的書遍地都是,代碼觸手可得。不是說你看看書,讀讀代碼就搞懂東西了。讀來的東西太淺,寫東西才會理解深刻。我對內核理解最深刻的部分,全都是在調試器里一行一行彙編跟蹤過的部分,多少年不搞了都忘不了。linux內核里各種奇葩的條件編譯和嵌套的宏定義往往會隱藏真相,萬事不過debug。多debug 可以更好的理解系統的ABI, 了解編譯器對代碼的處理,了解系統結構實現的細節。說到這裡,又跟前面提到的兩點結合起來了。

4 拓展知識面。只看Linux內核局限還是很明顯。比如Linux的中斷可以嵌套,這是為了更大的IO吞吐。而Win的中斷有優先順序,高優先順序中斷不被低優先順序中斷打斷,這是為了更好的桌面體驗。那麼MAC 是什麼選擇呢? 比如Linux 對異常的處理就是發信號,那Win是分層的結構化的異常回調機制,哪個更好呢?再比如,PC上的操作系統,硬體抽象層(HAL)都在內核里,而Android卻把HAL做到了用戶層,這是為什麼呢?到了內核的各個子系統,可對比的就更多了。搞Linux內核的人完全可以看看windows research kernel 的代碼。如果你們真的看明白了,你們就會明白微軟作為一個靠敲代碼敲出來的帝國,不是白給的。

殿堂? 不存在的,只有苦行僧。


首先, 先不要神話內核開發. 就是讀代碼, 改, 調試. 幾個月下來你就熟悉某一個小模塊了. 要知道, 很多人並不真的會寫c語言, 不妨礙他們讀, 改, 調內核.

比如我就面過mtk里做藍牙驅動開發, 愣是沒寫出strlen(). 這種大一C語言就不合格的人(是不合格, 不是不及格), 最後成為了開發者, 是非常常見的.


目前的工作實際上不是在搞 Linux 內核,但讀大學的 4 年,其中有兩年的時間在研究 Linux 內核和嵌入式 Linux。雖然已經好多年沒再搞 Linux 內核,但上次項目需要,還是分析調試了 Android 的 low memory killer 驅動,並給 Android 的 binder 驅動增加了一些功能,對於 Linux 的內核的基本分析調試能力一直在。看到這個問題,分享一下自己的做法。

以我的理解,題主的問題可以分解為三個小問題,Linux 內核開發需要知道的基本背景知識,Linux 內核開發研究在技術上的路線圖,以及 Linux 內核開發過程中的分析調試手法。

Linux 內核開發需要的基本背景知識。為什麼說是「基本」呢?主要是因為,如我們從操作系統原理一棵中所知道的那樣,操作系統內核都是分為基本大的子系統的,如 I/O,任務調度,內存管理,文件系統和網路等等,這些子系統都是演算法密集型的系統,不同子系統需要的背景知識還不太一樣。

Linux 內核主要是用 C 語言寫的,因而 C 語言開發的基本功必不可少。C 語言開發學習的經典著作很多,不僅有 C程序設計語言 這樣長生不衰的權威之作,還有,還有「C 語言開發的四書五經」和 C 語言開發——現代方法 這些非常好的作品。操作系統內核作為一個數據結構和演算法密集型的領域,基本的數據結構和演算法知識不可或缺,數據結構 這本必修課自不必說,其它還有演算法導論等等經典。

想要研究 Linux 內核,站在用戶的角度來看待它,了解它的功能和介面是必須的。誰是 Linux 內核的用戶,Linux 內核又為用戶提供了什麼功能,用戶又是通過什麼介面訪問這些功能的呢?Linux 內核功能主要是通過系統調用暴露給用戶的,系統調用通常又被封裝為 C 庫,需要使用操作系統內核功能的開發者通過 C 庫使用 Linux 內核。相關領域非常經典的著作是 UNIX環境高級編程(第3版),讀了這本書,應該就大體可以了解到,操作系統提供的大概就是文件操作,進程線程操作等功能了。程序員的自我修養 也值得一看,可以了解一下程序載入運行的過程。

然後是操作系統原理和計算機體系結構。用戶空間看到的操作系統功能和操作系統內部通常的設計結構並非嚴格對應的。通過操作系統原理,可以讓我們看到操作系統內部通常的設計結構,如通常的子系統劃分, I/O,任務調度,內存管理,文件系統和網路等,多個子系統的功能,都按照「一切皆文件」的 Unix 系統經典理念,通過文件有關的介面暴露給用戶空間。操作系統原理有關的經典著作有斯托林斯的 操作系統——精髓與設計原理,Andrew S·Tanenbaum 的 現代操作系統和操作系統設計與實現等,其中 操作系統設計與實現 還是 Linus 當年設計實現 Linux 內核時的主要參考。UNIX操作系統設計 和 Linux內核設計與實現 也非常經典,值得一讀,Linux內核設計與實現 的作者是 Linux 內核的核心開發者,還是內核搶佔子系統的作者。自己動手寫操作系統 也可以看一下。

Linux 內核研發是一個軟硬體結合的領域,計算機組成原理和體系結構相關的知識必不可少,彙編語言,CPU 的 MMU 等等都需要有所了解。相關的經典著作有 深入理解計算機系統 、計算機組成與設計硬體/軟體介面、ARM嵌入式系統開發 和 MIPS體系結構透視 等。答住過去關注的主要硬體平台是 ARM 的,因而關於 X86 平台的介紹,可以自行找涵蓋了 MMU/保護模式 的 X86 彙編語言有關的著作來研究。

Linux 內核開發需要的基本背景知識大概就是這些。

Linux 內核開發研究在技術上的路線圖。首先當然是從能夠快速上手,能夠快速帶來成就感的地方開始。硬體平台可以用自己日常使用的 PC 機,裝上 Linux 發行版,安裝必要的編譯鏈接等開發工具,差不多就可以上手了。Linux 內核的文檔非常齊全,可以用 Git 把 Linux 內核的源碼整個下載到本地,然後編譯一下,熟悉熟悉 Linux 內核的構建系統,畢竟在整個的 Linux 內核研發過程中需要與這套系統打交道的地方很多。

就 Linux 內核研究和開發本身來說,最簡單最方便的入手點就是驅動程序了。驅動程序可以從簡單的字元設備內存型驅動開始,編寫一個 「Hello world」字元設備驅動,暴露基本的文件操作,編譯並動態載入進內核,在通過文件操作訪問它時,可以讓它僅僅列印一個「Hello world」。當然內核不能使用 C 語言標準庫,內核列印的信息也不通過終端來看,而是通過 dmesg 命令來看。據說當前大多數的 Linux 內核研發工程師所做的工作,都是在搞驅動,驅動相關的代碼在 Linux 內核代碼中的佔比遠超一半。介紹 Linux 內核驅動的書很多,經典的長盛不衰但有點老的有 Linux設備驅動程序,還有 Linux設備驅動開發詳解 和 精通Linux驅動程序開發 等值得一讀。實際的 Linux 內核驅動當然不可能像「Hello world」字元設備驅動那麼簡單。實際編寫驅動時,硬體設備本身的協議需要仔細研讀,諸如硬體設備有幾個寄存器或者 IO 埠,對這些寄存器和 IO 埠的不同訪問方式可以訪問到什麼功能等等。此外在 Linux 內核中運行的驅動程序代碼,與內核中的其它子系統的交互幾乎是必不可少的,因而 Linux 驅動相關的書讀下來,會發現大部分都在講內核中的內存分配和管理,Linux 內核中的並發同步方法等等。嵌入式 Linux 系統有關的書會講許多關於硬體訪問方法的內容,值得一讀,如 嵌入式Linux應用開發完全手冊, ARM嵌入式系統基礎教程,嵌入式Linux基礎教程

很長時間沒有通過讀書來學習研究 Linux 內核,最近新出的書就不太了解了。不過在有了一定的基礎之後,研究 Linux 內核最好的方法就是,閱讀 Linux 內核官方相關模塊的文檔說明,閱讀 Linux 內核的代碼,然後做一些調試了。

研究學習 Linux 內核,除了從驅動入手外,也可以從另外兩個點入手,一是內核的啟動過程,二是系統調用。內核啟動和系統調用也都是離用戶最近的點,相對比較容易我們著手分析調試。

能夠上手寫一些 Linux 內核代碼,並對 Linux 內核開發中能夠用到的工具,如 Linux 內核提供的同步的函數,內存分配管理的函數等基礎有所了解之後,就可以根據自己的喜好和項目需要,來具體深入學習研究特定子系統了,如任務調度,內存管理,文件系統和網路等等。

總結一下,Linux 內核開發研究在技術上的路線圖大概是這樣的:代碼下載和構建 -&> 選擇從 Linux 驅動、內核的啟動過程或系統調用三者之一入手開始自己的內核開發之旅 -&> 學習 Linux 內核開發中能用到的工具和函數庫 -&> 根據工作和項目需要,選擇某個自己感興趣的子系統,如任務調度,內存管理,文件系統、IO、設備驅動和網路等等深入研究,完成自己的工作。

Linux 內核開發過程中的分析調試手法。硬體平台可以用自己的 PC 機,裝上 Linux 發行版,然後在上面做實驗。也可以用 ARM 平台做為硬體平台,可以買一塊 ARM 開發板或者 Google 的 Nexus 系列手機。用 Google 的 Nexus 系列手機時,可以參考 Google 提供的官方文檔來構建內核。不用硬體,用模擬器或虛擬機更方便,還不用擔心把電腦或手機變成磚。Android 模擬器用來研究 Linux 內核非常方便。分析調試可以通過打斷點或者列印日誌來做。用 Android 模擬器來打內核的斷點比較方便。

最後,樂者為王 是一本介紹 Linus 的書,非常有意思。關於 Unix 社區的一些文化和哲學有關的內容可以經常看一下。


被稱作「內核工程師」的其實有很多分類

  • 大多數都是做驅動的,特別是嵌入式。這個基本靠熟悉相關模塊的代碼,自己搞個out-of-tree module代碼質量也沒什麼要求,能跑就行 (抱歉,但看過的搞嵌入式的人寫的driver真的不敢恭維……)
  • 做相關上下游的時候順便修修bug提交給上游的,例如做cloud/virtualization碰到kernel bug掛了自己修一修。這個基本都集中在大廠的infra,部分不夠大的廠的號稱的「內核組」也做這個
  • 為了版本/ABI/.../穩定,維護自己的kernel版本,裁剪/backport需要的功能的,常見於大廠內核組,redhat在部分程度上也屬於這類,大廠內部一般也有專門的team做這個
  • 需要新的功能,能夠影響kernel開發方向的。這個看看linux foundation成員和Linux plumber conf都是哪些人就能知道了,因為加新功能是一個政治問題,不僅僅是個技術問題。fb和g家都有百人左右的內核團隊,最近搞的ebpf, xdp都屬於此類。由於內核團隊的小圈子特性,最好認識相關的前輩可以帶你進入社區


推薦閱讀:
相关文章