開篇html
學習內核,每一個人都有本身的學習方法,仁者見仁智者見智。如下是我在學習過程當中總結出來的東西,對自身來講,我認爲比較有效率,拿出來跟你們交流一下。linux
內核學習,一偏之見;疏漏不免,懇請指正。程序員
爲何寫這篇博客編程
剛開始學內核的時候,不要執着於一個方面,不要專一於一個子系統就一頭扎到實際的代碼行中去,由於這樣的話,牽涉的面會很廣,會碰到不少困難,容易產生挫敗感,一個函數體中(假設剛開始的時候正在學習某個方面的某個具體的功能函數)極可能摻雜着其餘各個子系統方面設計理念(可能是大量相關的數據結構或者全局變量,用於支撐該子系統的管理工做)下相應的代碼實現,這個時候看到這些東西,紛繁蕪雜,是沒有頭緒並且很不理解的,會產生不少不少的疑問,(這個時候若是對這些疑問糾纏不清,刨根問底,那麼事實上就是在學習當前子系統的過程當中頻繁的去涉足其餘子系統,這時候注意力就分散了),而事實上等了解了各個子系統後再回頭看這些東西的話,就簡單多了,並且思路也會比較清晰。因此,要避免 「只見樹木,不見森林」,不要急於深刻到底層代碼中去,不要過早研究底層代碼。安全
我在大二的時候剛開始接觸內核,就犯了這個錯誤,一頭扎到內存管理裏頭,去看很是底層的實現代碼,雖然也是創建在內存管理的設計思想的基礎上,可是相對來講,比較孤立,由於此時並無學習其它子系統,應該說不管是視野仍是思想,都比較狹隘,因此代碼中牽涉到的其它子系統的實現我都直接跳過了,這一點還算聰明,固然也是無可奈何的。網絡
個人學習方法數據結構
剛開始,我認爲主要的問題在於你知道不知道,而不是理解不理解,某個子系統的實現採用了某種策略、方法,而你在學習中須要作的就是知道有這麼一回事兒,而後纔是理解所描述的策略或者方法。多線程
根據本身的學習經驗,剛開始學習內核的時候,我認爲要作的是在本身的腦海中創建起內核的大致框架,理解各個子系統的設計理念和構建思想,這些理念和思想會從宏觀上呈獻給你清晰的脈絡,就像一個去除了枝枝葉葉的大樹的主幹,一目瞭然;固然,確定還會涉及到具體的實現方法、函數,可是此時接觸到的函數或者方法位於內核實現的較高的層次,是主(要)函數,已經瞭解到這些函數,針對的是哪些設計思想,實現了什麼樣的功能,達成了什麼樣的目的,混個臉熟的說法在這兒也是成立的。至於該主函數所調用的其它的輔助性函數就等同於枝枝葉葉了,沒必要太早就去深究。此時,也就初步創建起了內核子系統框架和代碼實現之間的關聯,關聯其實很簡單,好比一看到某個函數名字,就想起這個函數是針對哪一個子系統的,實現了什麼功能。架構
我認爲此時要看的就是LKD3,這本書算是泛泛而談,主要就是從概念,設計,大的實現方法上描述各個子系統,而對於具體的相關的函數實現的代碼講解不多涉及(對比於ULK3,此書主要就是關於具體函數代碼的具體實現的深刻分析,固然,你也能夠看,可是過早看這本書,會感受很痛苦,很枯燥無味,基本上都是函數的實現),不多,但不是沒有,這就很好,知足咱們當前的需求,還避免咱們過早深刻到實際的代碼中去。並且本書在一些重要的點上還給出了寫程序時的注意事項,算是指導性建議。主要的子系統包括:內存管理,進程管理和調度,系統調用,中斷和異常,內核同步,時間和定時器管理,虛擬文件系統,塊I/O層,設備和模塊。(這裏的前後順序其實就是LKD3的目錄的順序)。併發
我學習的時候是三本書交叉着看的,先看LKD3,專於一個子系統,主要就是了解設計的原理和思想,固然也會碰到對一些主要函數的介紹,但大多就是該函數基於前面介紹的思想和原理完成了什麼樣的功能,該書並無就函數自己的實現進行深刻剖析。而後再看ULK3和PLKA上看一樣的子系統,可是並不仔細分析底層具體函數的代碼,只是粗略地、不求甚解地看,甚至不看。由於,有些時候,在其中一本書的某個點上,卡殼了,不是很理解了,在另外的書上你可能就碰到對同一個問題的不一樣角度的描述,說不許哪句話就能讓你豁然開朗,如醍醐灌頂。我常常碰到這種狀況。
並非說學習過程當中對一些函數體的實現徹底就忽略掉,只要本身想完全瞭解其代碼實現,沒有誰會阻止你。我是在反覆閱讀過程當中慢慢深刻的。好比VFS中文件打開須要對路徑進行分析,須要考慮的細節很多(.././之類的),可是其代碼實現是很好理解的。再好比,CFS調度中根據shedule latency、隊列中進程個數及其nice值(使用的是動態優先級)計算出分配給進程的時間片,沒理由不看的,這個過重要了,並且也頗有意思。
ULK3也會有設計原理與思想之類的歸納性介紹,基本上都位於某個主題的開篇段落。可是更多的是對支持該原理和思想的主要函數實現的具體分析,一樣在首段,一句話綜述函數的功能,而後對函數的實現以一、二、3,或者a、b、c步驟的形式進行講解。我只是有選擇性的看,有時候對照着用source insight打開的源碼,確認一下代碼大致上確實是按書中所描述的步驟實現的,就當是增長感性認識。因爲步驟中摻雜着各類針對不一樣實現目的安全性、有效性檢查,若是不理解就先跳過。這並不妨礙你對函數體功能實現的總體把握。
PLKA介於LKD3和ULK3之間。我以爲PLKA的做者(看照片,真一德國帥小夥,技術如此了得)確定看過ULK,不管他的本意仍是有意,總之PLKA仍是跟ULK有所不一樣,對函數的仔細講解都作補充說明,去掉函數體中邊邊角角的狀況,好比一些特殊狀況的處理,有效性檢查等,而不妨礙對整個函數體功能的理解,這些他都有所交代,作了聲明;並且,就像LKD3同樣,在某些點上也給出了指導性編程建議。做者們甚至對同一個主要函數的講解的着重點都不同。這樣的話,對咱們學習的人而言,有助於加深理解。另外,我認爲很重要的一點就是PLKA針對的2.6.24的內核版本,而ULK是2.6.11,LKD3是2.6.34。在某些方面PLKA比較接近現代的實現。其實做者們之因此分別選擇11或者24,都是由於在版本發行樹中,這兩個版本在某些方面都作了不小的變更,或者說是具備標誌性的轉折點(這些信息大可能是在書中的引言部分介紹的,具體的細節我想不起來了)。
Intel V3,針對X86的CPU,本書天然是系統編程的權威。內核部分實現均可以在本書找到其根源。因此,在讀以上三本書某個子系統的時候,不要忘記能夠在V3中相應章節找到一些基礎性支撐信息。
在讀書過程當中,會產生至關多的疑問,這一點是確信無疑的。 大到搞不明白一個設計思想,小到不理解某行代碼的用途。各個方面,各類疑問,你徹底能夠把不理解的地方都記錄下來(不過,我並無這麼作,沒有把疑問所有記下來,只標記了不多一部分我認爲很關鍵的幾個問題),專門寫到一張紙上,不對,一個本上,我確信會產生這麼多的疑問,否則內核相關的論壇早就能夠關閉了。其實,大部分的問題(其中不少問題都是你知道不知道有這麼一回事的問題)均可以迎刃而解,只要你肯回頭再看,書讀百遍,其義自現。多看幾遍,前先後後的聯繫明白個七七八八是沒有問題的。我也這麼作了,針對某些子系統也看了好幾遍,切身體會。
當你按順序學習這些子系統的時候,前面的章節極可能會引用後面的章節,就像PLKA的做者說的那樣,徹底沒有向後引用是不可能的,他能作的只是儘可能減小這種引用而又不損害你對當前問題的理解。不理解,不要緊,跳過就好了。後面的章節一樣會有向前章節的引用,不過這個問題就簡單一些了 ,你能夠再回頭去看相應的介紹,當時你不太理解的東西,極可能這個時候就知道了它的設計的目的以及具體的應用。不求甚解只是暫時的。好比說,內核各個子系統之間的交互和引用在代碼中的體現就是實現函數穿插調用,好比你在內存管理章節學習了的內存分配和釋放的函數,而你是瞭解內存在先的,在學習驅動或者模塊的時候就會碰到這些函數的調用,這樣也就比較容易接受,不至於太過茫然;再好比,你瞭解了系統時間和定時器的管理,再回頭看中斷和異常中bottom half的調度實現,你對它的理解就會加深一層。
子系統進行管理工做須要大量的數據結構。子系統之間交互的一種方式就是各個子系統各自的主要數據結構經過指針成員相互引用。學習過程當中,參考書上在講解某個子系統的時候會對數據結構中主要成員的用途解釋一下,但確定不會覆蓋所有(成員比較多的狀況,例如task_struct),對其它子系統基於某個功能實現的引用可能解釋了,也可能沒作解釋,還可能說這個變量在何處會作進一步說明。因此,不要糾結於一個不理解的點上,暫且放過,回頭還能夠看的。之間的聯繫能夠在對各個子系統都有所瞭解以後再創建起來。其實,我仍然在強調先理解概念和框架的重要性。
等咱們完成了創建框架這一步,就能夠選擇一個比較感興趣的子系統,好比驅動、網絡,或者文件系統之類的。這個時候你再去深刻了解底層代碼實現,相較於一開始就鑽研代碼,更容易一些,並且碰到了不解之處,或者忘記了某個方面的實現,此時你徹底能夠找到相應的子系統,由於你知道在哪去找,查漏補缺,不只完成了對當前函數的鑽研,並且能夠回顧、溫習之前的內容,融會貫通的時機就在這裏了。
《深刻理解linux虛擬內存》(2.4內核版本),LDD3,《深刻理解linux網絡技術內幕》,幾乎每個子系統都須要一本書的容量去講解,因此說,剛開始學習不宜對某個模塊太過深刻,等對各個子系統都有所瞭解了,再有針對性的去學習一個特定的子系統。這時候對其它系統的援引均可以讓咱們再也不感到茫然、複雜,不知所云。
好比,LDD3中的如下所列章節:構造和運行模塊,併發和競態,時間、延遲及延緩操做,分配內存,中斷處理等,都屬於驅動開發的支撐性子系統,雖然說本書對這些子系統都專門開闢一個章節進行講解,可是詳細程度怎麼能比得上PLKA,ULK3,LKD3這三本書,看完這三本書,你會發現讀LDD3這些章節的時候簡直跟喝白開水同樣,太隨意了,由於LDD3的講解比之LKD3更粗略。打好了基礎,PCI、USB、TTY驅動,塊設備驅動,網卡驅動,須要瞭解和學習的東西就比較有針對性了。這些子系統就屬於通用子系統,瞭解以後,基於這些子系統的子系統的開發—驅動(需進一步針對硬件特性)和網絡(需進一步理解各類協議)—相對而言,其學習難度大大下降,學習進度大大加快,學習效率大大提高。說着容易作來難。達到這樣一種效果的前提就是:必須得靜下心來,認真讀書,要看得進去,PLKA,ULK3厚得都跟磚頭塊兒同樣,使人望之生畏,若是沒有興趣,沒有熱情,沒有毅力,不管如何都是不行,由於須要時間,須要很長時間。我並非說必須打好了基礎才能夠進行驅動開發,只是說打好了基礎的狀況下進行開發會更輕鬆,更有效率,並且本身對內核代碼的駕馭能力會更強大。這只是我我的看法,我本身的學習方式,僅供參考。
語言
PLKA是個德國人用德語寫的,後來翻譯成英文,又從英文翻譯成中文,我在網上書店裏沒有找到它的紙質英文版,因此就買了中文版的。ULK3和LKD3都是英文版的。大牛們寫的書,遣詞造句真的是簡潔,易懂,看原版對咱們學習計算機編程的程序員來講徹底不成問題,最好原汁原味。若是一本書確實翻譯地很好,咱們固然能夠看中文版的,用母語進行學習,理解速度和學習進度固然是很快的,不做他想。看英文的時候不要腦子裏想着把他翻譯成中文,不必。
API感想
「比起知道你所用技術的重要性,成爲某一個特別領域的專家是不重要的。知道某一個具體API調用一點好處都沒有,當你須要他的時候只要查詢下就行了。」這句話源於我看到的一篇翻譯過來的博客。我想強調的就是,這句話針應用型編程再合適不過,可是內核API就不徹底如此。
內核至關複雜,學習起來很不容易,可是當你學習到必定程度,你會發現,若是本身打算寫內核代碼,到最後要關注的仍然是API接口,只不過這些API絕大部分是跨平臺的,知足可移植性。內核***基本上已經標準化、文檔化了這些接口,你所要作的只是調用而已。固然,在使用的時候,最好對可移植性這一話題在內核中的編碼約定爛熟於心,這樣纔會寫出可移植性的代碼。就像應用程序同樣,可使用開發商提供的動態庫API,或者使用開源API。一樣是調用API,不一樣點在於使用內核API要比使用應用API瞭解的東西要多出許多。
當你瞭解了操做系統的實現—這些實現可都是對應用程序的基礎性支撐啊—你再去寫應用程序的時候,應用程序中用到的多線程,定時器,同步鎖機制等等等等,使用共享庫API的時候,聯繫到操做系統,從而把對該API的文檔描述同本身所瞭解到的這些方面在內核中的相應支撐性實現結合起來進行考慮,這會指導你選擇使用哪個API接口,選出效率最高的實現方式。對系統編程很有了解的話,對應用編程不無益處,甚至能夠說是大有好處。
設計實現的本質,知道仍是理解
操做系統是介於底層硬件和應用軟件之間的接口,其各個子系統的實現很大程度上依賴於硬件特性。書上介紹這些子系統的設計和實現的時候,咱們讀過了,也就知道了,若是再深刻考慮一下,爲何總體架構要按照這種方式組織,爲何局部函數要遵循這樣的步驟處理,知其然,知其因此然,若是你知道了某個功能的實現是由於芯片就是這麼設計的,CPU就是這麼作的,那麼你的疑問也就基本上到此爲止了。再深究,就是芯片架構方面的設計與實現,對於程序員來說,不管是系統仍是應用程序員,足跡探究到這裏,已經解決了不少疑問,由於咱們的工做性質偏軟,而這些東西實在是夠硬。
好比,ULK3中講解的中斷和異常的實現,究其根源,那是由於Intel x86系列就是這麼設計的,去看看Intel V3手冊中相應章節介紹,均可覺得ULK3中描述的代碼實現方式找到註解。還有時間和定時器管理,一樣能夠在Intel V3 對APIC的介紹中獲取足夠的信息,操做系統就是依據這些硬件特性來實現軟件方法定義的。
又是那句話,不是理解不理解的問題,而是知道不知道的問題。有時候,知道了,就理解了。在整個學習過程當中,知道,理解,知道,理解,知道……,交叉反覆。爲何開始和結尾都是知道,而理解只是中間步驟呢?世界上萬事萬物自有其規律,人類只是發現而已,實踐是第一位的,實踐就是知道的過程,實踐產生經驗,經驗的總結就是理論,理論源於實踐,理論才須要理解。咱們學習內核,深刻研究,搞來搞去,又回到了芯片上,芯片是物質的,芯片的功用基於天然界中物質本有的物理和電子特性。追本溯源,此之謂也。
動手寫代碼
紙上得來終覺淺,絕知此事要躬行。只看書是絕對不行的,必定要結合課本給出的編程建議本身敲代碼。剛開始就以模塊形式測試好了,或者本身編譯一個開發版本的內核。一臺機器的話,使用UML方式調試,內核控制路走到哪一步,單步調試看看程序執行過程,比書上的講解更直觀明瞭。必定要動手實際操做。
參考書
LDD3 Linux Device Driver 3rd
LKD3 Linux Kernel Development 3rd
ULK3 Understanding the Linux Kernel 3rd
PLKA Professional Linux Kernel Architecture
UML User Mode Linux
Intel V3 Intel? 64 and IA-32 Architectures Software Developer’s Manual Volume 3 (3A, 3B & 3C): System Programming Guide
做者在寫書的時候,都是以本身的理解組織內容,從本身的觀點看待一個主題,關注點跟做者自身有很大的關係。出書的時間有前後,後來人針對同一個主題想要出書而又不落入窠臼,最好有本身的切入方式,從本身的角度講解相關問題,這才值得出這本書,千篇一概是個掉價的行爲,書就不值錢了。
盡信書不如無書。
http://lwn.net/Articles/419855/ 此處是一篇關於LKD3的書評,指出了其中的錯誤,當你讀完的時候,不妨去找找,看一下本身在其中所描述的地方有什麼特別的印象。
http://lwn.net/Articles/161190/此處是一篇對ULK3的介紹,我認爲其中很關鍵的幾句話就能夠給本書定位:
Many of the key control paths in the kernel are described, step by step;
一步一步地講述內核控制路徑的實現。
The level of detail sometimes makes it hard to get a sense for the big picture, but it does help somebody trying to figure out how a particular function works.
對代碼講解的詳細程度有時候很難讓讀者把握住它的主旨大意,可是確實有助於讀者理解一個特定的函數究竟是如何工做的。
Indeed, that is perhaps the key feature which differentiates this book. It is very much a 「how it works」 book, designed to help people understand the code.
事實上,這也正是本書不同凡響的地方。更像一個「如何工做」的書,幫助讀者理解代碼實現。
It presents kernel functions and data structures, steps the reader through them, but does not, for example, emphasize the rules for using them. UTLK is a study guide, not a programming manual.
本書描述了內核函數和數據結構,引導讀者穿行於其間,可是,並無着重強調使用它們的法則。UTLK是一本學習指南,而不是編程手冊。
這幾句話對本書的描述很是到位。基於此,做爲指導性原則,咱們就能夠頗有效率地使用它了。
看一本技術書籍,書中的序言部分絕對是首先應該翻閱的,其次就是目錄。我發如今閱讀過程當中我會頻繁的查看目錄,甚至是喜歡看目錄。
結尾
興趣的力量是無窮的。興趣能帶來激情,若是工做能夠和興趣結合到一塊兒,工做起來纔會有熱情,那麼工做就不僅是工做了,更是一種享受。
Linux,個人興趣,個人動力,個人方向,個人將來!
來源:冰凌塊兒
blog.chinaunix.net/uid-24669930-id-4039377.html