歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux綜合 >> Linux內核

Linux內核學習經驗總結

開篇

學習內核,每個人都有自己的學習方法,仁者見仁智者見智。以下是我在學習過程中總結出來的東西,對自身來說,我認為比較有效率,拿出來跟大家交流一下。​

內核學習,一偏之見;疏漏難免,懇請指正。

為什麼寫這篇博客

剛開始學內核的時候,不要執著於一個方面,不要專注於一個子系統就一頭扎到實際的代碼行中去,因為這樣的話,牽涉的面會很廣,會碰到很多困難,容易產生挫敗感,一個函數體中(假設剛開始的時候正在學習某個方面的某個具體的功能函數)很可能摻雜著其他各個子系統方面設計理念(多是大量相關的數據結構或者全局變量,用於支撐該子系統的管理工作)下相應的代碼實現,這個時候看到這些東西,紛繁蕪雜,是沒有頭緒而且很不理解的,會產生很多很多的疑問,(這個時候如果對這些疑問糾纏不清,刨根問底,那麼事實上就是在學習當前子系統的過程中頻繁的去涉足其他子系統,這時候注意力就分散了),而事實上等了解了各個子系統後再回頭看這些東西的話,就簡單多了,而且思路也會比較清晰。所以,要避免 “只見樹木,不見森林”,不要急於深入到底層代碼中去,不要過早研究底層代碼。

我在大二的時候剛開始接觸內核,就犯了這個錯誤,一頭扎到內存管理裡頭,去看非常底層的實現代碼,雖然也是建立在內存管理的設計思想的基礎上,但是相對來說,比較孤立,因為此時並沒有學習其它子系統,應該說無論是視野還是思想,都比較狹隘,所以代碼中牽涉到的其它子系統的實現我都直接跳過了,這一點還算聰明,當然也是迫不得已的。

我的學習方法

剛開始,我認為主要的問題在於你知道不知道,而不是理解不理解,某個子系統的實現采用了某種策略、方法,而你在學習中需要做的就是知道有這麼一回事兒,然後才是理解所描述的策略或者方法。

根據自己的學習經驗,剛開始學習內核的時候,我認為要做的是在自己的腦海中建立起內核的大體框架,理解各個子系統的設計理念和構建思想,這些理念和思想會從宏觀上呈獻給你清晰的脈絡,就像一個去除了枝枝葉葉的大樹的主干,一目了然;當然,肯定還會涉及到具體的實現方法、函數,但是此時接觸到的函數或者方法位於內核實現的較高的層次,是主(要)函數,已經了解到這些函數,針對的是哪些設計思想,實現了什麼樣的功能,達成了什麼樣的目的,混個臉熟的說法在這兒也是成立的。至於該主函數所調用的其它的輔助性函數就等同於枝枝葉葉了,不必太早就去深究。此時,也就初步建立起了內核子系統框架和代碼實現之間的關聯,關聯其實很簡單,比如一看到某個函數名字,就想起這個函數是針對哪個子系統的,實現了什麼功能。

我認為此時要看的就是LKD3,這本書算是泛泛而談,主要就是從概念,設計,大的實現方法上描述各個子系統,而對於具體的相關的函數實現的代碼講解很少涉及(對比於ULK3,此書主要就是關於具體函數代碼的具體實現的深入分析,當然,你也可以看,但是過早看這本書,會感覺很痛苦,很枯燥無味,基本上都是函數的實現),很少,但不是沒有,這就很好,滿足我們當前的需求,還避免我們過早深入到實際的代碼中去。而且本書在一些重要的點上還給出了寫程序時的注意事項,算是指導性建議。主要的子系統包括:內存管理,進程管理和調度,系統調用,中斷和異常,內核同步,時間和定時器管理,虛擬文件系統,塊I/O層,設備和模塊。(這裡的先後順序其實就是LKD3的目錄的順序)。

我學習的時候是三本書交叉著看的,先看LKD3,專於一個子系統,主要就是了解設計的原理和思想,當然也會碰到對一些主要函數的介紹,但大多就是該函數基於前面介紹的思想和原理完成了什麼樣的功能,該書並沒有就函數本身的實現進行深入剖析。然後再看ULK3和PLKA上看同樣的子系統,但是並不仔細分析底層具體函數的代碼,只是粗略地、不求甚解地看,甚至不看。因為,有些時候,在其中一本書的某個點上,卡殼了,不是很理解了,在另外的書上你可能就碰到對同一個問題的不同角度的描述,說不准哪句話就能讓你豁然開朗,如醍醐灌頂。我經常碰到這種情況。

並不是說學習過程中對一些函數體的實現完全就忽略掉,只要自己想徹底了解其代碼實現,沒有誰會阻止你。我是在反復閱讀過程中慢慢深入的。比如VFS中文件打開需要對路徑進行分析,需要考慮的細節不少(.././之類的),但是其代碼實現是很好理解的。再比如,CFS調度中根據shedule latency、隊列中進程個數及其nice值(使用的是動態優先級)計算出分配給進程的時間片,沒理由不看的,這個太重要了,而且也很有意思。

ULK3也會有設計原理與思想之類的概括性介紹,基本上都位於某個主題的開篇段落。但是更多的是對支持該原理和思想的主要函數實現的具體分析,同樣在首段,一句話綜述函數的功能,然後對函數的實現以1、2、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都是英文版的。大牛們寫的書,遣詞造句真的是簡潔,易懂,看原版對我們學習計算機編程的程序員來說完全不成問題,最好原汁原味。如果一本書確實翻譯地很好,我們當然可以看中文版的,用母語進行學習,理解速度和學習進度當然是很快的,不作他想。看英文的時候不要腦子裡想著把他翻譯成中文,沒必要。
Copyright © Linux教程網 All Rights Reserved