出版時(shí)間:2009-08-01 出版社:電子工業(yè)出版社 作者:李云華 頁(yè)數(shù):482
Tag標(biāo)簽:無(wú)
前言
幾乎每一個(gè)操作系統(tǒng)內(nèi)核的學(xué)習(xí)者在初學(xué)階段都會(huì)感覺(jué)到難以入門(mén)。這是由于內(nèi)核涉及到知識(shí)面非常廣泛,需要學(xué)習(xí)者從根本上掌握大量的知識(shí),這包括:程序編譯,鏈接,裝載的細(xì)節(jié),操作系統(tǒng)理論,計(jì)算機(jī)系統(tǒng)體系結(jié)構(gòu),數(shù)據(jù)結(jié)構(gòu)與算法,深厚的C/匯編語(yǔ)言編程功底。如此相對(duì)較高的門(mén)檻常常令很大一部分初學(xué)者望而卻步。那么是不是一定要先學(xué)好以上的各門(mén)知識(shí)后才能學(xué)習(xí)內(nèi)核呢?事實(shí)上大部分學(xué)習(xí)者在學(xué)習(xí)以上各門(mén)知識(shí)都會(huì)遇到同樣的問(wèn)題,因?yàn)橹R(shí)是一個(gè)網(wǎng)狀結(jié)構(gòu)。所以重要的不是先去學(xué)會(huì)什么知識(shí),而是學(xué)會(huì)如何學(xué)習(xí),學(xué)會(huì)在自己掌握的知識(shí)體系上提出問(wèn)題,學(xué)會(huì)思考,進(jìn)而堅(jiān)持不懈的解決心中的疑問(wèn)。筆者從學(xué)完C/C++ 語(yǔ)言開(kāi)始,由于C/C++ 的示例程序都是在命令行下的,于是常常想如何才能編寫(xiě)出視窗程序,學(xué)習(xí)了MFC,但是同樣想不通諸如WM_CHAR,WM_LBUTTONDOWN 的消息從何而來(lái),帶著MFC 中諸多疑問(wèn),筆者開(kāi)始學(xué)習(xí)Windows SDK 程序開(kāi)發(fā),在這個(gè)學(xué)習(xí)過(guò)程中感覺(jué)對(duì)MFC 的認(rèn)識(shí)更加深入了,但同時(shí)又有新的問(wèn)題想不通,于是進(jìn)而學(xué)習(xí)Windows DDK,之后開(kāi)始學(xué)習(xí)操作系統(tǒng)內(nèi)核。在這個(gè)過(guò)程中,筆者也遇到過(guò)數(shù)不盡的疑問(wèn),但是都是需要的時(shí)候再補(bǔ)充相關(guān)知識(shí)。因此初學(xué)者要明白,學(xué)習(xí)并不需要等到“萬(wàn)事具備”了才可以開(kāi)始。需要的是保持好奇心,養(yǎng)成思考的習(xí)慣,樹(shù)立解決問(wèn)題的決心。很多讀者渴望尋找好的入門(mén)教材,也常常有人問(wèn)看什么書(shū)才能進(jìn)步的快,但是當(dāng)他們看了別人推薦的書(shū)卻沒(méi)有取得同樣的收獲,這是為什么呢?筆者認(rèn)為,讀書(shū)有以下幾種境界: 1. 面對(duì)書(shū)上講到的某個(gè)知識(shí)點(diǎn),不能接合自己掌握的知識(shí)提出疑問(wèn),僅僅知識(shí)死記書(shū)本上的東西。這種狀態(tài)就算學(xué)到最高境界,也僅僅只是能把書(shū)本上的知識(shí)點(diǎn)完好的記下來(lái)在腦海中形成孤立的知識(shí)節(jié)點(diǎn)?! ?. 面對(duì)書(shū)本上講到的某個(gè)知識(shí)點(diǎn),能接合自己掌握的知識(shí)提出疑問(wèn),但是大多數(shù)時(shí)候沒(méi)有探索精神,僅僅局限于到其他書(shū)籍或者請(qǐng)教別人來(lái)排除心中的疑問(wèn)。腦海中的知識(shí)形成了簡(jiǎn)單網(wǎng)狀結(jié)構(gòu),但由于探索能力長(zhǎng)期得不到鍛煉,綜合自己的知識(shí)去分析和解決問(wèn)題的能力十分有限?! ?. 面對(duì)書(shū)上講到的某個(gè)知識(shí)點(diǎn),能接合自己掌握的知識(shí)提出疑問(wèn),并且能根據(jù)問(wèn)題補(bǔ)充相關(guān)必要的知識(shí),不斷綜合分析各知識(shí)點(diǎn)的關(guān)系,提出各種假設(shè)和驗(yàn)證排除的方法并親自驗(yàn)證,解決不了問(wèn)題決不罷休。如能經(jīng)過(guò)長(zhǎng)期鍛煉,其腦海中的知識(shí)點(diǎn)形成復(fù)雜的網(wǎng)狀結(jié)構(gòu),綜合分析能力必將加強(qiáng)?! ?. 根據(jù)自己掌握的知識(shí),提出全新的問(wèn)題,并始終堅(jiān)持找到答案為止。這種境界需要淵博的知識(shí)作為基礎(chǔ)?! ∫虼?,不要還沒(méi)學(xué)內(nèi)核就被嚇倒,說(shuō)了這么多看似和內(nèi)核無(wú)關(guān)的東西,就是要從先排除讀者的心理?yè)?dān)憂,樹(shù)立正確的態(tài)度,重要的不是學(xué)會(huì)什么,而是學(xué)會(huì)學(xué)習(xí)。確定自己處于哪一種學(xué)習(xí)境界,然后通過(guò)學(xué)習(xí)某項(xiàng)具體的知識(shí)把自己提升到更高的境界。在現(xiàn)實(shí)生活中我們不難發(fā)現(xiàn),能力強(qiáng)的學(xué)什么都又快又好。其根本原因在于他們處于更高的學(xué)習(xí)境界,并形成了良性循環(huán)! 有很多的人都渴望學(xué)習(xí)操作系統(tǒng)內(nèi)核,但是內(nèi)核涉及到的知識(shí)非常廣泛,因此很多人半途而廢,許多人往往抱怨沒(méi)有好的書(shū)籍,教材。實(shí)際上,對(duì)于同一本書(shū)籍,不同的讀者收獲也是不同的,這取決于他們的態(tài)度和學(xué)習(xí)方法。筆者建議,在讀書(shū)的時(shí)候,一定要以自己心中的疑問(wèn)作為主線,而不要沒(méi)有任何疑問(wèn)就死記書(shū)本上的知識(shí)。 如何使用本書(shū) 筆者認(rèn)為對(duì)于任何知識(shí)的學(xué)習(xí),首先是以自我為中心,任何書(shū)籍資料都是用來(lái)解答讀者心中的疑問(wèn)的,因此在你閱讀一本書(shū)時(shí),首先要明確自己的疑問(wèn)是什么?這可以是一個(gè)非常梗概的問(wèn)題,例如:“Linux 內(nèi)核是什么?”;也可以是一個(gè)非常細(xì)節(jié)的問(wèn)題,例如:“按下鍵盤(pán)上的A,到屏幕上顯示出字符A 的內(nèi)部原理”。當(dāng)你有了來(lái)自內(nèi)心深處經(jīng)過(guò)獨(dú)立思考的疑問(wèn)后,閱讀對(duì)你來(lái)說(shuō)是一種享受,一種樂(lè)趣。來(lái)自內(nèi)心的疑問(wèn),經(jīng)過(guò)不斷的綜合分析,縝密的推理,堅(jiān)持不懈的查閱和求索,之后撥開(kāi)迷霧見(jiàn)天日喜悅只有經(jīng)過(guò)才能體會(huì)。雖然本書(shū)是一本很厚的書(shū),但是這不是畏懼的理由,也不要因?yàn)樗瘢徒o自己下一個(gè)決心,制定一個(gè)閱讀計(jì)劃,幾個(gè)月要讀完本書(shū)。學(xué)習(xí)是主動(dòng)探求的過(guò)程,而不是被動(dòng)接受,在這個(gè)過(guò)程中,有太多的東西,不是誰(shuí)可以計(jì)劃出來(lái)的。例如:在筆者學(xué)習(xí)內(nèi)核之初,看到大量的傳言,讀完《Understanding the linux Kernel》,讀完《Linux 內(nèi)核情景分析》... 就可以成為“高手”了。于是筆者常常捧著厚厚的書(shū),尋思著自己什么時(shí)候可以讀完,然而有時(shí)好幾天也前進(jìn)不了幾頁(yè),免不了感慨自己今生將與“高手”無(wú)緣,但是又心有不甘,于是囫圇吞棗的“快速”前進(jìn),但是越前進(jìn),就越感覺(jué)到艱難?!坝賱t不達(dá)”這個(gè)道理人人都懂,但是在切身體會(huì)之前,人人都會(huì)犯這個(gè)錯(cuò)誤。在經(jīng)歷了很長(zhǎng)一段曲折和郁悶之后,筆者擺脫了“書(shū)”的束縛,完全以自己的疑問(wèn)為中心,例如在讀到中斷處理時(shí),由于知識(shí)不夠全面,于是丟開(kāi)內(nèi)核的書(shū)籍,閱讀了大量的計(jì)算機(jī)體系結(jié)構(gòu)方面的資料,同樣計(jì)算機(jī)體系結(jié)構(gòu)的書(shū)籍也很厚,但是我也沒(méi)有想過(guò)要把它們讀完,這時(shí)只撿中斷相關(guān)的讀,之后再來(lái)讀內(nèi)核的書(shū)籍,發(fā)現(xiàn)自己原理懂了,但是具體到理解代碼時(shí),就迷糊了,于是有補(bǔ)充GCC 內(nèi)嵌匯編,C 代碼編譯到匯編代碼的相關(guān)知識(shí),反復(fù)試驗(yàn)等等。這個(gè)過(guò)程很慢,但是積累到最后,筆者發(fā)現(xiàn)自己讀的非???,甚至可以不讀了,因?yàn)楹芏嗟胤?,只要讀到前面的,就領(lǐng)悟了作者后面想要說(shuō)什么了?! ≈两?,我仍然沒(méi)有完成當(dāng)初為了成為“高手”而制定下的“宏偉”目標(biāo),因?yàn)槲覜](méi)有完整的讀完《Understanding the Linux Kernel》、《Linux 內(nèi)核情景分析》或《Linux 內(nèi)核完全剖析》等等這類(lèi)傳說(shuō)中“驚世駭俗”之作中的任何一本。但是筆者卻從這些著作中受益菲淺。 現(xiàn)在,你應(yīng)該知道要如何使用本書(shū)了吧?那就是不要拘泥如任何教條。雖然本書(shū)經(jīng)筆者從初學(xué)到現(xiàn)在的心得體會(huì)以及相關(guān)筆記和資料整理而成,初學(xué)者的大量疑問(wèn)都能在本書(shū)本書(shū)中找到答案。但是每個(gè)人都是獨(dú)一無(wú)二的,筆者希望任何一個(gè)讀者能綜合利用本書(shū)和其它相關(guān)資料尋找你自己的答案。多問(wèn)一點(diǎn)為什么,多一點(diǎn)假設(shè),多一點(diǎn)思考,多一點(diǎn)推理,多一點(diǎn)試驗(yàn),多一點(diǎn)堅(jiān)持。最后,你會(huì)感慨原來(lái)傳說(shuō)中的任何“秘籍”都是“浪得虛名”,因?yàn)樽x完它,你不一定能成為“高手”,而“高手”卻不需要讀完它。能否成為“高手”的決定性因素取決于你的學(xué)習(xí)方法和學(xué)習(xí)態(tài)度,而好的“秘籍”僅僅只是催化劑。
內(nèi)容概要
《獨(dú)辟蹊徑品內(nèi)核:Linux內(nèi)核源代碼導(dǎo)讀》根據(jù)最新的2.6.24內(nèi)核為基礎(chǔ)。在講述方式上,《獨(dú)辟蹊徑品內(nèi)核:Linux內(nèi)核源代碼導(dǎo)讀》注重實(shí)例分析,盡量在討論“如何做”的基礎(chǔ)上,深入討論為什么要這么做,從而實(shí)現(xiàn)《獨(dú)辟蹊徑品內(nèi)核:Linux內(nèi)核源代碼導(dǎo)讀》的寫(xiě)作宗旨:“授人以漁”。在內(nèi)容安排上,《獨(dú)辟蹊徑品內(nèi)核:Linux內(nèi)核源代碼導(dǎo)讀》包含以下章節(jié)x86硬件基礎(chǔ);基礎(chǔ)知識(shí);Linux內(nèi)核Makefile分析;Linux內(nèi)核啟動(dòng);內(nèi)存管理;中斷和異常處理;系統(tǒng)調(diào)用;信號(hào)機(jī)制在類(lèi)UNIX系統(tǒng)中;時(shí)鐘機(jī)制;進(jìn)程管理;調(diào)度器;文件系統(tǒng);常用內(nèi)核分析方法?! 丢?dú)辟蹊徑品內(nèi)核:Linux內(nèi)核源代碼導(dǎo)讀》適合初、中級(jí)Linux用戶、從事內(nèi)核相關(guān)開(kāi)發(fā)的從業(yè)人員,也可以作為各類(lèi)院校相關(guān)專(zhuān)業(yè)的教材及Linux培訓(xùn)班的教材,也可作為L(zhǎng)inux內(nèi)核學(xué)習(xí)的專(zhuān)業(yè)參考書(shū)。
作者簡(jiǎn)介
李云華,是一名內(nèi)核技術(shù)的狂熱愛(ài)好者,長(zhǎng)期從事操作系統(tǒng)內(nèi)核、計(jì)算機(jī)網(wǎng)絡(luò)、設(shè)備驅(qū)動(dòng)程序、以及嵌入系統(tǒng)方面的開(kāi)發(fā)和研究。擁有豐富的設(shè)備驅(qū)動(dòng)開(kāi)發(fā)、網(wǎng)絡(luò)優(yōu)化、內(nèi)核及驅(qū)動(dòng)移植、嵌入式系統(tǒng)構(gòu)建等方面的開(kāi)發(fā)經(jīng)驗(yàn)。對(duì)Windows內(nèi)核驅(qū)動(dòng)及Linux內(nèi)核驅(qū)動(dòng)均有豐富的開(kāi)發(fā)經(jīng)驗(yàn)及心得體會(huì)。
書(shū)籍目錄
第1章 x86硬件基礎(chǔ)11.1 保護(hù)模式11.1.1 分頁(yè)機(jī)制11.1.2 分段機(jī)制71.2 系統(tǒng)門(mén)131.3 x86的寄存器141.4 典型的PC系統(tǒng)結(jié)構(gòu)簡(jiǎn)介16第2章 基礎(chǔ)知識(shí)182.1 AT&T與Intel匯編語(yǔ)法比較182.2 gcc內(nèi)嵌匯編202.3 同步與互斥252.3.1 原子操作252.3.2 信號(hào)量272.3.3 自旋鎖292.3.4 RCU機(jī)制352.3.5 percpu變量392.4 內(nèi)存屏障412.4.1 編譯器引起的內(nèi)存屏障412.4.2 緩存引起的內(nèi)存屏障442.4.3 亂序執(zhí)行引起的內(nèi)存屏障472.5 高級(jí)語(yǔ)言的函數(shù)調(diào)用規(guī)范49第3章 Linux內(nèi)核Makefile分析523.1 Linux內(nèi)核編譯概述523.2 內(nèi)核編譯過(guò)程分析543.3 內(nèi)核鏈接腳本分析62第4章 Linux內(nèi)核啟動(dòng)654.1 BIOS啟動(dòng)階段654.2 實(shí)模式setup階段674.3 保護(hù)模式startup_32774.4 內(nèi)核啟動(dòng)start_kernel()844.5 內(nèi)核啟動(dòng)時(shí)的參數(shù)傳遞904.5.1 內(nèi)核參數(shù)處理914.5.2 模塊參數(shù)處理95第5章 內(nèi)存管理995.1 內(nèi)存地址空間995.1.1 物理內(nèi)存地址空間995.1.2 虛擬地址空間1015.2 內(nèi)存管理的基本數(shù)據(jù)結(jié)構(gòu)1045.2.1 物理內(nèi)存頁(yè)面描述符1045.2.2 內(nèi)存管理區(qū)1065.2.3 非一致性內(nèi)存管理1085.3 內(nèi)存管理初始化1095.3.1 bootmemalloctor的初始化1095.3.2 頁(yè)表初始化1155.3.3 內(nèi)存管理結(jié)構(gòu)的初始化1185.4 內(nèi)存的分配與回收1275.4.1 伙伴算法1275.4.2 SLUB分配器138第6章 中斷與異常處理1526.1 中斷的分類(lèi)1526.2 中斷的初始化1566.2.1 異常初始化1566.2.2 中斷的初始化1606.2.3 中斷請(qǐng)求服務(wù)隊(duì)列的初始化1676.3 中斷與異常處理1716.3.1 特權(quán)轉(zhuǎn)換與堆棧變化1716.3.2 中斷處理1726.3.3 異常處理1776.4 軟件中斷與延遲函數(shù)1806.4.1 softirq1806.4.2 tasklet1856.5 中斷與異常返回1876.6 中斷優(yōu)先級(jí)回顧1916.7 關(guān)于高級(jí)可編程中斷控制器1926.7.1 APIC初始化193第7章 信號(hào)機(jī)制1997.1 信號(hào)機(jī)制的管理結(jié)構(gòu)2007.2 信號(hào)發(fā)送2047.3 信號(hào)處理210第8章 系統(tǒng)調(diào)用2208.1 Libc和系統(tǒng)調(diào)用220第9章 時(shí)鐘機(jī)制2269.1 clocksource對(duì)象2279.1.1 clocksource概述2279.1.2 clocksource初始化2289.2 tickless機(jī)制2329.2.1 tickless由來(lái)2329.2.2 clockeventdevice對(duì)象概述2349.2.3 clockeventdevice對(duì)象的初始化2369.3 High-ResolutionTimers2479.3.1 High-ResolutionTimers管理結(jié)構(gòu)2479.3.2 High-ResolutionTimers初始化2529.3.3 High-ResolutionTimers操作2589.4 時(shí)鐘中斷處理2689.4.1 時(shí)鐘維護(hù)2769.4.2 進(jìn)程時(shí)間信息統(tǒng)計(jì)2819.5 軟件定時(shí)器2839.5.1 基本管理結(jié)構(gòu)2839.5.2 初始化2849.5.3 注冊(cè)與過(guò)期處理287第10章 進(jìn)程管理29510.1 進(jìn)程描述符29610.1.1 進(jìn)程狀態(tài)29710.1.2 進(jìn)程標(biāo)識(shí)29910.1.3 進(jìn)程的親緣關(guān)系30010.1.4 進(jìn)程的內(nèi)核態(tài)堆棧30110.1.5 進(jìn)程的虛擬內(nèi)存布局30210.1.6 進(jìn)程的文件信息30510.2 進(jìn)程的建立30610.2.1 建立子進(jìn)程的task_struct對(duì)象30810.2.2 子進(jìn)程的內(nèi)存區(qū)域31510.2.3 子進(jìn)程的內(nèi)核態(tài)堆棧32310.2.4 0號(hào)進(jìn)程的建立32510.3 進(jìn)程切換32710.4 進(jìn)程的退出33110.4.1 do_exit函數(shù)33110.4.2 task_struct結(jié)構(gòu)的刪除33410.4.3 通知父進(jìn)程33510.5 do_wait()函數(shù)33810.6 程序的加載344第11章 調(diào)度器35111.1 早期的調(diào)度器35111.2 CFS調(diào)度器的虛擬時(shí)鐘35311.3 CFS調(diào)度器的基本管理結(jié)構(gòu)35711.4 CFS調(diào)度器對(duì)象35911.5 CFS調(diào)度操作36011.5.1 update_curr()函數(shù)36011.5.2 scheduler_tick()函數(shù)36211.5.3 put_prev_task_fair()函數(shù)36411.5.4 pick_next_task()函數(shù)36611.5.5 等待和喚醒操作36811.5.6 nice系統(tǒng)調(diào)用373第12章 文件系統(tǒng)37612.1 Ext2的磁盤(pán)結(jié)構(gòu)37612.2 Ext2的內(nèi)存結(jié)構(gòu)38512.3 虛擬文件系統(tǒng)的管理結(jié)構(gòu)38712.3.1 文件系統(tǒng)對(duì)象38812.3.2 VFS的超級(jí)塊38912.3.3 VFS的inode結(jié)構(gòu)40012.3.4 VFS的文件對(duì)象40612.3.5 VFS的目錄對(duì)象40912.3.6 VFS在進(jìn)程中的文件結(jié)構(gòu)41212.4 文件系統(tǒng)的掛載41312.5 路徑定位42512.6 文件打開(kāi)與關(guān)閉44112.7 文件讀寫(xiě)44912.7.1 緩沖區(qū)管理44912.7.2 文件讀寫(xiě)操作分析456第13章 常用內(nèi)核分析方法47113.1 準(zhǔn)確定位同名宏及結(jié)構(gòu)體47113.2 準(zhǔn)確定位同名函數(shù)47313.3 利用linkmap文件定位全局變量47413.4 準(zhǔn)確定位函數(shù)調(diào)用線索47613.5 SystemTap在代碼分析中的使用479
章節(jié)摘錄
第1章 x86硬件基礎(chǔ) 如果你是一個(gè)Linux內(nèi)核初學(xué)者,你一定常常遇到:保護(hù)模式,分段機(jī)制,分頁(yè)機(jī)制,段地址,線性地址,中斷門(mén),調(diào)用門(mén),局部描述符,全局描述符,等等這樣的名詞。這些概念常常把初學(xué)者弄得“云里來(lái),霧里去”。你會(huì)常常感慨,Intel為什么要設(shè)計(jì)這么復(fù)雜的概念呢??jī)H僅是一個(gè)地址機(jī)制,就常常讓初學(xué)者打開(kāi)書(shū)本,發(fā)現(xiàn)自己會(huì)算了,可是一旦關(guān)上書(shū)本,換個(gè)例子,又迷惑了?! ∈聦?shí)上這些機(jī)制的背后都有它的緣由,任何一個(gè)復(fù)雜的設(shè)計(jì)都是由一個(gè)簡(jiǎn)單的設(shè)計(jì)發(fā)展起來(lái)的,當(dāng)簡(jiǎn)單的設(shè)計(jì)滿足不了實(shí)際需要時(shí),就會(huì)一步一步地革新,直到問(wèn)題被圓滿地解決。因此理解一個(gè)“復(fù)雜”的東西的最好方式不是去記住它,而是要從最簡(jiǎn)單的地方入手,一步一步地推敲,簡(jiǎn)單的設(shè)計(jì)在現(xiàn)實(shí)中會(huì)遇到什么問(wèn)題?又該如何解決這個(gè)問(wèn)題?再聯(lián)系到你現(xiàn)在要理解的復(fù)雜的例子,慢慢地建立起一條完整的線索,這樣知識(shí)不會(huì)出現(xiàn)斷層,你也不需要一次跨越一個(gè)鴻溝,一切都水到渠成。例如:在學(xué)習(xí)保護(hù)模式中的地址機(jī)制時(shí),你一定會(huì)感覺(jué)為什么要這么復(fù)雜呢?實(shí)模式不是很簡(jiǎn)單嗎?既然實(shí)模式簡(jiǎn)單,那么不妨想想,如果使用實(shí)模式會(huì)遇到什么問(wèn)題呢?把這些問(wèn)題都一一列出來(lái),再結(jié)合現(xiàn)有機(jī)制,你就會(huì)很自然的理解為什么需要這么做了。本章將試圖讓讀者看到這些概念背后的“為什么”?! ?.1 保護(hù)模式 1.1.1 分頁(yè)機(jī)制 內(nèi)存按字節(jié)編址,每個(gè)地址對(duì)應(yīng)一個(gè)字節(jié)的存儲(chǔ)單元,早期的程序直接使用物理地址。在單任務(wù)操作系統(tǒng)時(shí)代,物理內(nèi)存被劃分為兩部分,一部分地址空間由操作系統(tǒng)使用,另外一部分由應(yīng)用程序使用。到了多任務(wù)時(shí)代,由于程序中的全局變量,起始加載地址是在鏈接期決定的。如果直接使用物理地址,則很可能有多個(gè)起始地址一致的應(yīng)用程序需要同時(shí)被加載運(yùn)行,這就需要把沖突的程序加載到另外的地址上去,然后重新修正程序中的所有相關(guān)的全局符號(hào)的地址。然而在早期的計(jì)算機(jī)系統(tǒng)上內(nèi)存容量十分有限,即便是通過(guò)重定位解決了加載地址沖突的問(wèn)題,由于內(nèi)存大小的限制,能夠同時(shí)加載運(yùn)行的程序仍然十分有限。而在多任務(wù)系統(tǒng)上,某些進(jìn)程在部分時(shí)間內(nèi)處于等待狀態(tài),于是人們很自然地想到,當(dāng)內(nèi)存不夠的時(shí)候把處于等待狀態(tài)的進(jìn)程換入磁盤(pán),騰出一些內(nèi)存空間來(lái)加載新程序。這又帶來(lái)了新的問(wèn)題:每次騰出來(lái)的空間地址可不是固定不變的,這就意味著把磁盤(pán)上的內(nèi)容加載進(jìn)來(lái)的時(shí)候,又要重新修正程序中的相關(guān)地址,在每次換入換出的過(guò)程中要不斷地修正相關(guān)程序的地址。而且還有一個(gè)更為嚴(yán)重的問(wèn)題:假設(shè)進(jìn)程A出現(xiàn)一個(gè)錯(cuò)誤,對(duì)某個(gè)物理地址進(jìn)行了寫(xiě)入操作,恰好這個(gè)地址又屬于進(jìn)程B,當(dāng)進(jìn)程B被調(diào)度運(yùn)行的時(shí)候,必然會(huì)出現(xiàn)錯(cuò)誤。很難想象一個(gè)軟件產(chǎn)品的BuG卻導(dǎo)致用戶抱怨另外一個(gè)軟件產(chǎn)品。于是虛擬內(nèi)存技術(shù)發(fā)展起來(lái)。在虛擬內(nèi)存中,程序代碼中訪問(wèn)的不再是物理地址,而是虛擬地址?! ∫?2位系統(tǒng)為例,每一個(gè)進(jìn)程有4GB的虛擬地址空間,每個(gè)進(jìn)程中有一個(gè)表,它記錄著每個(gè)虛擬地址對(duì)應(yīng)的物理地址是多少,這樣當(dāng)程序加載的時(shí)候,可以先分配好物理內(nèi)存,然后把物理內(nèi)存的地址填入這個(gè)表里面,這樣進(jìn)程之間互不影響。假設(shè)程序A和B都是要求在地址BASE處加載(程序中使用的都是虛擬地址。),由于每個(gè)進(jìn)程都有4GB的私有虛擬地址空間,因此兩個(gè)進(jìn)程沒(méi)有加載沖突。操作系統(tǒng)分配的物理地址分別是A1和B1,然后A1和B1起始的物理內(nèi)存地址分別被填入兩個(gè)進(jìn)程虛擬地址映射表中,從而建立虛擬地址和物理地址的一一映射關(guān)系。當(dāng)進(jìn)程A訪問(wèn)虛擬地址BAsE+X的時(shí)候,由于MMu的硬件支持,硬件自動(dòng)查找進(jìn)程A的地址映射表,從而訪問(wèn)到物理地址為A1+x的內(nèi)存單元。同理,當(dāng)進(jìn)程B訪問(wèn)虛擬地址為BAsE+x的時(shí)候,MMU自動(dòng)查找進(jìn)程B的地址映射。表,從而訪問(wèn)到B1+X的內(nèi)存單元。當(dāng)然,實(shí)際上的虛擬地址機(jī)制比這個(gè)復(fù)雜得多,但是在對(duì)它又了總體認(rèn)識(shí)之后,再來(lái)學(xué)習(xí)一個(gè)實(shí)際的例子就要簡(jiǎn)單得多了。接下來(lái)就以32位的x86系統(tǒng)為例,進(jìn)一步介紹虛擬內(nèi)存機(jī)制?! ∶總€(gè)進(jìn)程擁有4GB的虛擬地址空間,每個(gè)字節(jié)的虛擬地址可以通過(guò)地址映射表映射到一個(gè)字節(jié)的物理地址上面去。因此這個(gè)映射表本身必然要占據(jù)很大的內(nèi)存空間,如何設(shè)計(jì)映射表成為問(wèn)題的關(guān)鍵。如果在虛擬地址映射表中為每一個(gè)字節(jié)建立映射關(guān)系,那么映射4GB的虛擬地址需要230×4B(32位系統(tǒng)地址為4Byte)的內(nèi)存??梢?jiàn)簡(jiǎn)單的一一填表映射是不能滿足現(xiàn)實(shí)要求的。為了要減少虛擬地址映射表項(xiàng)占用的內(nèi)存空問(wèn),所有操作系統(tǒng)都采用了頁(yè)式管理。把物理內(nèi)存劃分為4KB,8KB或者16KB大小的頁(yè),這樣每個(gè)頁(yè)面在虛擬地址映射表中僅僅占用4Byte的內(nèi)存。以4KB的頁(yè)大小為例,4GB的虛擬地址空間有220個(gè)頁(yè)面,那么映射4GB空間的映射表僅僅需要220×4B(32系統(tǒng)地址為4Bvte)的內(nèi)存。 其映射原理如圖1.1所示:程序要訪問(wèn)的地址是0x12345A10,cPu中的MMu首先找到這個(gè)進(jìn)程的虛擬地址映射表,其起始物理地址為0x10000000。在4KB頁(yè)大小的情況下,4GB虛擬地址空間含有220個(gè)頁(yè)面,只需要20位就可以表示220的大小了,所以虛擬地址的高20位0x12345作為虛地址映射表中的索引,在32位系統(tǒng)上虛地址映射表中的每一項(xiàng)是4個(gè)字節(jié),所以MMu根據(jù)地址0X10000000+0X123454取得虛擬地址0x12345A10對(duì)應(yīng)的物理頁(yè)面起始地址為0x54321000,該地址的低12位總是為0,這是由于每一個(gè)4KB.大小的物理頁(yè)面總是在4KB的邊界上對(duì)齊的。而虛地址Oxl2345A10中的低12位被用伽頁(yè)內(nèi)偏移量,最終虛地址0x12345A10對(duì)應(yīng)的物理地址為0x54321000+A10,而CPU訪問(wèn)到的內(nèi)容是0x12345678?! ∮捎陧?yè)大小為4KB,虛地址表中的表項(xiàng)低12位總是為0,因此可以把低12位用來(lái)做標(biāo)識(shí)位。例如把第0位用做存在位,當(dāng)?shù)?位為1時(shí)表示該頁(yè)面在物理內(nèi)存中,反之表示該頁(yè)面不在物理內(nèi)存中。假設(shè)一個(gè)進(jìn)程要占用10MB的內(nèi)存空間,在進(jìn)程初始化的時(shí)候,虛地址映射表初始化為0,在內(nèi)存不足的情況下,系統(tǒng)只分配了5MB的內(nèi)存,這5MB內(nèi)存的物理地址被填入到映射表中,同時(shí)表項(xiàng)中最低位被設(shè)置成1,當(dāng)進(jìn)程訪問(wèn)到另外5MB的虛地址的時(shí)候,MMU在查表時(shí)發(fā)現(xiàn)最低位為0,于是觸發(fā)一個(gè)缺頁(yè)中斷,這個(gè)時(shí)候,系統(tǒng)缺頁(yè)中斷處理例程再分配內(nèi)存頁(yè)面,同時(shí)更新相應(yīng)的映射表項(xiàng),之后程序就可以正常運(yùn)行了?! ⊥?,還可以把一位劃分出來(lái)作為讀寫(xiě)位,如果對(duì)一個(gè)地址進(jìn)行寫(xiě)入操作,MMu在查表的時(shí)候會(huì)根據(jù)其讀寫(xiě)位判斷是否允許寫(xiě)入。幾乎每一個(gè)程序員都知道訪問(wèn)NuLL指針時(shí),一定會(huì)出錯(cuò),那么操作系統(tǒng)是如何捕捉到這個(gè)錯(cuò)誤的呢?地址0(NULL)實(shí)實(shí)在在地對(duì)應(yīng)了內(nèi)存中的一個(gè)物理內(nèi)存地址,如何根據(jù)一個(gè)地址來(lái)判斷指針是不是合法的呢?各個(gè)操作系統(tǒng)都保證在一個(gè)進(jìn)程中虛擬地址從0開(kāi)始的某一段區(qū)域是不映射的,其頁(yè)表項(xiàng)為0。例如windows中把0~64K的地址區(qū)域劃分到NULL指針區(qū)而不被映射。因此訪問(wèn)這部分地址的時(shí)候必然會(huì)觸發(fā)缺頁(yè)中斷,這個(gè)時(shí)候操作系統(tǒng)就可以判斷出這個(gè)地址是否落在NuLL指針區(qū)內(nèi)。否則無(wú)論像malloc這一類(lèi)的函數(shù)返回的指針是0還是其他的值,都無(wú)法判斷分配成功或是失敗。
編輯推薦
較新的內(nèi)核版本:本書(shū)使用的內(nèi)核版本為2.6.24?! —?dú)特的寫(xiě)作手法:本書(shū)在討論“How”的基礎(chǔ)上,力求進(jìn)一步探究“Why”?! 笆谌艘詽O”的寫(xiě)作宗旨:Linux內(nèi)核處于飛速發(fā)展中,任何資料都無(wú)法覆蓋內(nèi)核的方方面面。配收以筆者學(xué)習(xí)過(guò)程的疑問(wèn)和經(jīng)驗(yàn)為基礎(chǔ),融會(huì)貫通于各個(gè)章節(jié),毫無(wú)保留地就如何學(xué)習(xí)內(nèi)核,如何分析內(nèi)核進(jìn)行了大量且大膽的探討,從而力求體現(xiàn)本書(shū)的寫(xiě)作宗旨——“授人以漁”。
圖書(shū)封面
圖書(shū)標(biāo)簽Tags
無(wú)
評(píng)論、評(píng)分、閱讀與下載
250萬(wàn)本中文圖書(shū)簡(jiǎn)介、評(píng)論、評(píng)分,PDF格式免費(fèi)下載。 第一圖書(shū)網(wǎng) 手機(jī)版