




免費(fèi)預(yù)覽已結(jié)束,剩余1頁可下載查看
下載本文檔
版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
Linux內(nèi)核啟動(dòng)(詳細(xì))在內(nèi)核成功裝入內(nèi)存(如果需要就解壓縮)以及一些關(guān)鍵硬件,例如已經(jīng)在低層設(shè)置過的內(nèi)存管理器(MMU,請(qǐng)參見第8章)之后,內(nèi)核將跳轉(zhuǎn)到start_kernel(19802行)。這個(gè)函數(shù)完成其余的系統(tǒng)初始化工作實(shí)際上,幾乎所有的初始化工作都是由這個(gè)函數(shù)實(shí)現(xiàn)的。因此,start_kernel就是本節(jié)的核心。start_kernel19802:_init標(biāo)示符在gcc編譯器中指定將該函數(shù)置于內(nèi)核的特定區(qū)域。在內(nèi)核完成自身初始化之后,就試圖釋放這個(gè)特定區(qū)域。實(shí)際上,內(nèi)核中存在兩個(gè)這樣的區(qū)域,.text.init和.data.init第一個(gè)是代碼初始化使用的,另外一個(gè)是數(shù)據(jù)初始化使用的(可以在進(jìn)程間共享的代碼和字符串常量之類的“文本(Text)”是在可執(zhí)行程序中的“純區(qū)域”中使用的一個(gè)術(shù)語)。另外你也可以看到_initfunc和_initdata標(biāo)志,前者和_init類似,標(biāo)志初始化專用代碼,后者則標(biāo)志初始化專用數(shù)據(jù)。19807:如前所述,即使在多處理器系統(tǒng)中,在啟動(dòng)時(shí)也只使用一個(gè)CPU。Intel稱之為引導(dǎo)程序處理器(bootstrap processor,簡(jiǎn)稱為BSP),它在內(nèi)核代碼的某些地方有時(shí)也稱之為BP。BSP首次運(yùn)行這一行時(shí),跳過后面的if語句,并減小boot_cpu標(biāo)志,從而當(dāng)其他CPU運(yùn)行到此處時(shí),都要運(yùn)行if語句。等到其他CPU被激活執(zhí)行到這里時(shí),BSP已經(jīng)在idle循環(huán)中了(本章稍后會(huì)更詳細(xì)地討論這個(gè)問題),initialize_secondary(4355行)負(fù)責(zé)把其他CPU加入到BSP中。這樣,其他CPU就不用執(zhí)行start_kernel的剩余部分了這也是一件好事,因?yàn)檫@意味著不用再對(duì)許多硬件進(jìn)行冗余初始化等工作了。順便說一下,這種奇異的小小的改動(dòng)只有對(duì)于x86是必需的;對(duì)于其他平臺(tái),調(diào)用smp_init完全可以處理SMP設(shè)置的其他部分。因此,其他平臺(tái)的initialize_secondary的定義都是空的。19816:打印內(nèi)核標(biāo)題信息(20099行),這里顯示了有關(guān)內(nèi)核如何編譯的信息,包括在什么機(jī)器上編譯,什么時(shí)間編譯,使用什么版本的編譯器,等等。如果中間任何一步發(fā)生了錯(cuò)誤,在尋找機(jī)器不能啟動(dòng)的原因時(shí)查明內(nèi)核的來源是一個(gè)有用的線索。19817:初始化內(nèi)核自身的部分組件內(nèi)存、硬件中斷、調(diào)度程序,等等。尤其是setup_arch函數(shù)(19765行)完成體系結(jié)構(gòu)相關(guān)的設(shè)置,此后在command_line(傳遞到內(nèi)核的參數(shù),在下面討論)、memory_start和memory_end(內(nèi)核可用物理地址范圍)中返回結(jié)果。下面這些函數(shù)都希望駐留在內(nèi)存低端,它們使用memory_start和memory_end來傳遞該信息。在函數(shù)獲得所希望的值后,返回值指明了新的memory_start的值。19823:分析傳給內(nèi)核的各種選項(xiàng)。parse_options函數(shù)(19707行,在隨后的“分析內(nèi)核選項(xiàng)”一節(jié)中討論)也設(shè)置了argv和envp的初值。19833:內(nèi)核運(yùn)行過程中也可以自行對(duì)所進(jìn)行的工作進(jìn)行記錄,周期性地對(duì)所執(zhí)行的指令進(jìn)行抽樣,并使用所獲得的結(jié)果更新表格。這在定時(shí)器中斷過程中通過調(diào)用x86_do_profile(1896行)來實(shí)現(xiàn),該部分將在第6章中介紹。如圖4-1中說明的那樣,這個(gè)表格把內(nèi)核劃分為幾個(gè)大小相同的范圍,并簡(jiǎn)單跟蹤在一次中斷的時(shí)間內(nèi)每個(gè)范圍中運(yùn)行多少條指令。這種記錄當(dāng)然是非常粗糙的甚至不是依據(jù)函數(shù)和行號(hào)進(jìn)行劃分的,而只是使用近似的地址但是這樣代價(jià)很低,且快速、短小,而且有助于專家判斷最關(guān)鍵的問題。每個(gè)表格條目所涉及到地址的多少還有問題發(fā)生地點(diǎn)的不確定性可以通過簡(jiǎn)單修改prof_shift(26142行)來調(diào)節(jié)。profile_setup(19076行,在本章中后面討論)可以讓你在啟動(dòng)的時(shí)候設(shè)置prof_shift的值,這樣比為修改這個(gè)數(shù)字而重新編譯內(nèi)核要清晰方便得多。圖4-1 描述用緩存這個(gè)if程序塊為記錄表格分配內(nèi)存,并把所有項(xiàng)都清零。注意到如果prof_shift是0(默認(rèn)值),那么記錄功能就被關(guān)掉了,if程序塊不再被執(zhí)行,也不為表格分配空間。19846:內(nèi)核通過調(diào)用sti(UP版本的13104行,注意該主題在第6章中有更詳細(xì)的介紹)開始接收硬件中斷。首先需要激活定時(shí)器中斷,以便后來對(duì)calibrate_delay(19654行)的調(diào)用可以計(jì)算機(jī)器的BogoMIPS的值(在下一節(jié)“BogoMIPS”中介紹)。因?yàn)橐恍┰O(shè)備驅(qū)動(dòng)程序需要BogoMIPS的值,所以內(nèi)核必需在大部分硬件、文件系統(tǒng)等等初始化之前計(jì)算出這個(gè)值來。19876:測(cè)試該CPU的各種缺陷,比如Pentium F00F缺陷(請(qǐng)參見第8章),記錄檢測(cè)到的缺陷,以便于內(nèi)核的其他部分以后可以使用它們工作。(為了節(jié)省空間起見,我們省略掉了check_bugs函數(shù)。)19882:調(diào)用smp_init(19787行),它又調(diào)用了其他的函數(shù)來激活SMP系統(tǒng)中的其他CPU:在x86的平臺(tái)上,smp_boot_cpus(4614行)初始化一些內(nèi)核數(shù)據(jù)結(jié)構(gòu),這些數(shù)據(jù)結(jié)構(gòu)跟蹤檢測(cè)另外的CPU并簡(jiǎn)單的將其改為保持模式;最后smp_commence(4195行)使這些CPU繼續(xù)執(zhí)行。19883:把init函數(shù)作為內(nèi)核線程終止,這比較復(fù)雜;請(qǐng)參閱本章后面有關(guān)init的討論。19885:增加idle進(jìn)程的need_resched標(biāo)志,這樣做的原因此時(shí)可能還比較模糊。當(dāng)讀完了第5、6、7章以后,就會(huì)有個(gè)清楚的概念;但是,在下一個(gè)定時(shí)器中斷結(jié)束之前(在第6章中討論),system_call(171行,在第5章中討論)函數(shù)中會(huì)注意到idle進(jìn)程的need_resched標(biāo)志增加了,并且調(diào)用schedule(26686行,第7章)釋放CPU,并將其賦給更應(yīng)該獲取CPU的進(jìn)程。19886:已經(jīng)完成了內(nèi)核初始化的工作或者不管怎樣,已經(jīng)把需要完成的少量責(zé)任傳遞給了init,所剩余的工作不過是進(jìn)入idle循環(huán)以消耗空閑的CPU時(shí)間片。因此,本行調(diào)用cpu_idle(2014行)idle循環(huán)。正如你可以從cpu_idle本身可以發(fā)現(xiàn)的一樣,該函數(shù)從不返回。然而,當(dāng)有實(shí)際工作要處理時(shí),該函數(shù)就會(huì)被搶占。注意到cpu_idle只是反復(fù)調(diào)用idle系統(tǒng)調(diào)用(下一章將討論系統(tǒng)調(diào)用),它通過sys_idle(2064行)實(shí)現(xiàn)真正的idle循環(huán)2014行對(duì)應(yīng)UP版本,2044行針對(duì)SMP版本。它們通過執(zhí)行hlt(對(duì)應(yīng)“halt”)指令把CPU轉(zhuǎn)入低功耗的“睡眠”狀態(tài)。只要沒有實(shí)際的工作處理,CPU都將轉(zhuǎn)入這種狀態(tài)。4.2.1 BogoMIPSBogoMIPS的數(shù)字由內(nèi)核計(jì)算并在系統(tǒng)初始化的時(shí)候打印。它近似給出了每秒鐘CPU可以執(zhí)行一個(gè)短延遲循環(huán)的次數(shù)。在內(nèi)核中,這個(gè)結(jié)果主要用于需要等待非常短周期的設(shè)備驅(qū)動(dòng)程序例如,等待幾微秒并查看設(shè)備的某些信息是否已經(jīng)可用。由于沒有正確理解BogoMIPS的含義,BogoMIPS在各處都被濫用,就仿佛它可以滿足人類最原始、最深層次的需求:把所有計(jì)算機(jī)性能的信息簡(jiǎn)化為一個(gè)數(shù)字?!癇ogoMIPS”中的“Bogo”部分來源于“偽(bogus)”,就正是為了防止這種用法:雖然這個(gè)數(shù)字比大多數(shù)基準(zhǔn)測(cè)試數(shù)大,但是它仍然是不準(zhǔn)確的、容易引起誤解的、無用的和不真實(shí)的,根本不適合將它用于機(jī)器間差別的對(duì)比。但是這個(gè)數(shù)字仍然非常吸引人,這也正是我們?cè)谶@里討論這個(gè)問題的原因。(BogoMIPS 中“MIPS”部分是“millions of instructions per second(百萬條指令每秒)”的縮寫,這是cpu基準(zhǔn)測(cè)試中的一個(gè)常用單位。)calibrate_delay19654:calibrate_delay是近似計(jì)算BogoMIPS數(shù)字的內(nèi)核函數(shù)。19622:作為第一次估算,calibrate_delay計(jì)算出在每一秒內(nèi)執(zhí)行多少次_delay循環(huán)(6866行),也就是每個(gè)定時(shí)器滴答(timer tick)百分之一秒內(nèi)延時(shí)循環(huán)可以執(zhí)行多少次。19664:計(jì)算一個(gè)定時(shí)器滴答內(nèi)可以執(zhí)行多少次循環(huán)需要在滴答開始時(shí)就開始計(jì)數(shù),或者應(yīng)該盡可能與它接近。全局變量jiffies(16588行)中存儲(chǔ)了從內(nèi)核開始保持跟蹤時(shí)間開始到現(xiàn)在已經(jīng)經(jīng)過的定時(shí)器滴答數(shù);第6章中將介紹它的實(shí)現(xiàn)方式。jiffies保持異步更新,在一個(gè)中斷內(nèi)每秒一百次,內(nèi)核暫時(shí)掛起正在處理的內(nèi)容,更新變量,然后繼續(xù)剛才的工作。如果不這樣處理,下一行的循環(huán)就永遠(yuǎn)不可能退出。從而,如果jiffies不聲明為volatile簡(jiǎn)單地說,這個(gè)值變化的原因?qū)τ诰幾g器是透明的,gcc仍然可能對(duì)該循環(huán)進(jìn)行優(yōu)化,并引起該循環(huán)進(jìn)入不能退出的狀態(tài)。雖然目前的gcc還沒有如此高的智能,然而它的維護(hù)者應(yīng)該完全能夠?yàn)樗鼘?shí)現(xiàn)這種智能。19669:定時(shí)器又前移了一個(gè)滴答,因此又產(chǎn)生一個(gè)新的滴答。下一步是要等待loops_per_sec延時(shí)循環(huán)調(diào)用定時(shí)器循環(huán),接著檢測(cè)是否最少有一個(gè)完整的滴答已經(jīng)完成。如果是這樣,就退出首次近似估算循環(huán);如果沒有,就把loops_per_sec的值加倍,然后重新啟動(dòng)這個(gè)過程。這個(gè)循環(huán)的正確性依賴于如下的事實(shí):現(xiàn)有的機(jī)器在任何地方都不能每秒執(zhí)行232次延時(shí)循環(huán)(對(duì)于64位機(jī)來說則遠(yuǎn)低于每秒264次),雖然這只是一個(gè)微不足道的問題。19677:現(xiàn)在內(nèi)核已經(jīng)清楚loops_per_sec循環(huán)調(diào)用延時(shí)循環(huán)在這臺(tái)機(jī)器上要花費(fèi)超過百分之一秒的時(shí)間才能完成,因此,內(nèi)核將重新開始進(jìn)行估算。為了提高效率,內(nèi)核使用折半查找算法計(jì)算loops_per_sec的實(shí)際值,我們假定開始的時(shí)候,實(shí)際值在現(xiàn)在計(jì)算結(jié)果和其一半之間實(shí)際值不可能比現(xiàn)在計(jì)算值還大,但是可以(而且可能)稍微小一點(diǎn)。19681:和前面使用的方式一樣,calibrate_delay查看這個(gè)loops_per_sec已經(jīng)減小了的值是否還是比較大,而需要耗費(fèi)一個(gè)完整的定時(shí)器間隔。如果還是相當(dāng)大,實(shí)際值應(yīng)該小于當(dāng)前計(jì)算值或者就是當(dāng)前值,因此,使用更小的值繼續(xù)查詢;如果不夠大,就使用一個(gè)更大的值繼續(xù)查詢。19691:內(nèi)核有一種很好的方法來計(jì)算一個(gè)定時(shí)器滴答中執(zhí)行延時(shí)循環(huán)的次數(shù)。這個(gè)數(shù)字乘以一秒內(nèi)滴答的數(shù)量就得到了每秒內(nèi)可以執(zhí)行的延時(shí)循環(huán)的次數(shù)。這種計(jì)算只是一種估算,乘法也累積了誤差,因此結(jié)果并不能精確到納秒。但是這個(gè)數(shù)字供內(nèi)核使用已經(jīng)足夠精確了。19693:為了讓用戶感到激動(dòng),內(nèi)核打印出這個(gè)數(shù)字。注意這里明顯省略了%f的格式限定內(nèi)核盡量避免浮點(diǎn)數(shù)運(yùn)算。這個(gè)計(jì)算過程中最有用的常量是500 000;它是用一百萬除以2得來,理由是每秒鐘執(zhí)行一百萬條指令,而每個(gè)delay循環(huán)的核心是2條指令(decl和一條跳轉(zhuǎn)指令)。4.2.2 分析內(nèi)核選項(xiàng)parse_options函數(shù)分析由內(nèi)核引導(dǎo)程序發(fā)送給內(nèi)核的啟動(dòng)選項(xiàng),在初始化過程中按照某些選項(xiàng)運(yùn)行,并將剩余部分傳送給init進(jìn)程(在本章后面部分提到)。這些選項(xiàng)可能已經(jīng)存儲(chǔ)在配置文件中了,也可能是由用戶在系統(tǒng)啟動(dòng)時(shí)敲入的內(nèi)核并不關(guān)心這些。類似的細(xì)節(jié)全部是內(nèi)核引導(dǎo)程序應(yīng)該關(guān)注的內(nèi)容。1. parse_options19707:參數(shù)已經(jīng)收集在一條長(zhǎng)的命令行中,內(nèi)核被賦給指向該命令行頭部的一個(gè)指針;內(nèi)核引導(dǎo)程序在前面已經(jīng)將該行存儲(chǔ)在一個(gè)指定地址中。19718:中斷下一個(gè)參數(shù),保持指向下一個(gè)參數(shù)的指針以供下一次循環(huán)使用。注意系統(tǒng)使用空格而不是通常的空白來分隔內(nèi)核參數(shù);制表符并不能把當(dāng)前參數(shù)和下一個(gè)參數(shù)分隔開。如果發(fā)現(xiàn)了分隔字符空格,下一行就使用字節(jié)0覆蓋,這樣line可以作為包含有唯一一個(gè)內(nèi)核選項(xiàng)的標(biāo)準(zhǔn)C字符串來使用了。如果沒有發(fā)現(xiàn)空格,就該函數(shù)關(guān)心的內(nèi)容而言,其余的部分都具有相同的屬性這只有在處理line中最后一個(gè)選項(xiàng)的情況下才會(huì)發(fā)生,循環(huán)就會(huì)在下次開始時(shí)結(jié)束。注意該代碼不會(huì)跳過多個(gè)空格。假設(shè)line值如下所述(兩個(gè)空格):rw debug這會(huì)被當(dāng)作三個(gè)選項(xiàng):“rw”、“”(空字符串)和“debug”。因?yàn)榭兆址皇怯行У膬?nèi)核選項(xiàng),它將會(huì)被傳遞到初始化的過程(這一點(diǎn)隨后就可以看到)這當(dāng)然不是用戶所希望的。因此,內(nèi)核引導(dǎo)程序應(yīng)該負(fù)責(zé)對(duì)多個(gè)空格進(jìn)行壓縮。LILO通過忽略用戶多敲的空格,完美地解決了這個(gè)問題。19721:現(xiàn)在開始解釋這些選項(xiàng)。最前面的兩個(gè)選項(xiàng)ro和rw指明內(nèi)核要裝載根文件系統(tǒng),也就是根目錄( / 目錄)所在的位置,而分別處于只讀和讀/寫模式。19729:第三種可能性,debug,增加了調(diào)試信息的數(shù)量;這些調(diào)試信息要通過調(diào)用do_syslog打印出來(25724行)。19733:開始幾個(gè)選項(xiàng)是簡(jiǎn)單的獨(dú)立標(biāo)志,它們并不使用參數(shù)。內(nèi)核也可以辨認(rèn)形為option=value的選項(xiàng)。本行就是一個(gè)例子,這里內(nèi)核引導(dǎo)程序定義了一個(gè)命令來代替init運(yùn)行;它使用init=/some/other/program的形式。這里的代碼舍棄了init= 部分,為隨后init的使用而把剩余部分在execute_command中保存起來(20044行)。和其他大部分參數(shù)的處理方法不同,本處功能不能在checksetup(19612行)中實(shí)現(xiàn),這是因?yàn)樗淖兞嗽摵瘮?shù)的局部變量。很快,你就可以看到前面三個(gè)選項(xiàng)之所以也在這里處理,而不是在checksetup中處理的原因。19745:大部分內(nèi)核選項(xiàng)都是由checksetup函數(shù)分析的。如果checksetup處理了某個(gè)選項(xiàng),就返回真值,循環(huán)繼續(xù)進(jìn)行。19750:否則,line中沒有已經(jīng)被辨認(rèn)的內(nèi)核選項(xiàng)。在這種情況下,它被作為一個(gè)供init進(jìn)程使用的選項(xiàng)或者環(huán)境變量來處理如果其形式為envar=value,就作為環(huán)境變量處理;否則,就作為選項(xiàng)處理。如果argv_init和envp_init(分別見19057和19059行)數(shù)組中有足夠的空間,選項(xiàng)和環(huán)境變量就存儲(chǔ)在里面供以后init函數(shù)使用。這解釋了從19736行開始的注釋。字符串a(chǎn)uto并不是任何內(nèi)核選項(xiàng)的前綴,因此它應(yīng)該被作為init的一個(gè)參數(shù)存儲(chǔ)在argv_init數(shù)組中這在大多數(shù)情況下都是可行的,因?yàn)閍uto是init可以識(shí)別的選項(xiàng)。但是,當(dāng)使用init=的形式給出內(nèi)核選項(xiàng)時(shí),通常是執(zhí)行shell而不是init,auto會(huì)使shell混淆;因此,安全一點(diǎn)的方法是,parse_options在此處忽略所有與此有關(guān)的init參數(shù)。奇怪的是,當(dāng)argv_init或者envp_init數(shù)組空間用完時(shí),整個(gè)循環(huán)就結(jié)束了。僅僅因?yàn)閍rgv_init的空間用完了并不意味著line中就不再含有init使用的環(huán)境變量,反之亦然。此外,可能還剩下許多內(nèi)核選項(xiàng)沒有處理。當(dāng)你考慮到MAX_INIT_ARGS(19029行)和MAX_INIT_ENVS(19030行)都通過使用#define被預(yù)定義為8這是一個(gè)很容易超過的下限,這種行為就更奇怪了。如果在19752行和19756行的break改成continue,那么循環(huán)可以繼續(xù)處理內(nèi)核選項(xiàng),而不會(huì)寫入超過argv_init和envp_init數(shù)組界限的空間。如果command_line中仍然包含有并不是為init而定義的內(nèi)核選項(xiàng),那么這一點(diǎn)就是非常重要的。19760:所有的內(nèi)核選項(xiàng)都處理完成了。最后一步是要使用NULL填充argv_init和envp_init數(shù)組的末尾,從而使得init可以知道在哪里終止。2. checksetup19612:checksetup函數(shù)負(fù)責(zé)進(jìn)行大部分內(nèi)核選項(xiàng)的處理過程。它把這些內(nèi)核選項(xiàng)分為三類:一類使用內(nèi)核普通參數(shù)來分析=sign之后的部分;另一類自行分析=sign之后的部分;還有一類自行分析整個(gè)行,包括= sign前面的部分和= sign后面的部分。第一類被認(rèn)為是使用“現(xiàn)成”的參數(shù),這與為第二類提供的“原始”參數(shù)相對(duì)應(yīng)。最后一類只由一個(gè)IDE驅(qū)動(dòng)程序組成;內(nèi)核首先在19619行檢查并處理這種情況,以使其不會(huì)在隨后的處理中造成麻煩。19625:接下來,checksetup掃描整個(gè)raw_params數(shù)組(19552行),并判斷是否該內(nèi)核選項(xiàng)應(yīng)該不加處理地保留。raw_params中的元素是struct kernel_param類型(19223行)的,它把內(nèi)核選項(xiàng)前綴和裝載選項(xiàng)時(shí)調(diào)用的函數(shù)聯(lián)系起來。如果數(shù)組中的某些項(xiàng)的str成員以line為前綴,就會(huì)調(diào)用line后面的相應(yīng)函數(shù)(也就是前綴之后的部分),隨后checksetup會(huì)返回一個(gè)非零值以表明它已經(jīng)對(duì)該內(nèi)核選項(xiàng)進(jìn)行了處理。raw_params數(shù)組以兩個(gè)NULL結(jié)束,因此在檢測(cè)到str成員是NULL時(shí),循環(huán)就可以結(jié)束了。在這種情況下,顯然循環(huán)已經(jīng)到達(dá)了raw_params數(shù)組的結(jié)尾,但是仍然沒有找到匹配的情況。當(dāng)然,測(cè)試setup_func成員也可以取得同樣好的效果。這個(gè)循環(huán)說明了一點(diǎn):與大多數(shù)內(nèi)核非常不同的是,這里的初始化并不需要盡可能地快。如果內(nèi)核比從前多用幾微秒來啟動(dòng),這并沒有什么實(shí)際的損失畢竟用戶應(yīng)用程序還沒有開始運(yùn)行,所以他們并沒有損失什么東西。最終結(jié)果是代碼效率很低,而且存在很多優(yōu)化的可能。例如,raw_params數(shù)組中字符串的長(zhǎng)度可以在raw_params中暫存,而不用在19626行多次重復(fù)計(jì)算。更好的解決方法是,可以把raw_params數(shù)組中的項(xiàng)按照字符順序排序,這樣checksetup就可以進(jìn)行折半查找。在raw_params的情況中實(shí)現(xiàn)排序并沒有什么障礙,但是這樣也可能并不能獲得很大的優(yōu)勢(shì),因?yàn)檎郯氩檎业膬?yōu)點(diǎn)只有在比較大的數(shù)組中才能充分表現(xiàn)出來(所謂比較大的確切值在不同的環(huán)境中也有所不同)。raw_params的姊妹數(shù)組cooked_params(19228行)當(dāng)然是足夠大的,可以顯示出折半查找的優(yōu)勢(shì);但是這樣就引發(fā)了一個(gè)新的問題:對(duì)cooked_params進(jìn)行排序比較難用,因?yàn)檫@可能需要分隔一些#ifdef程序段請(qǐng)參看從19268行到19272行的例子。進(jìn)一步說,因?yàn)樗惴ㄖ皇遣檎仪熬Y,而不使用完全匹配,在遍歷數(shù)組中的各個(gè)項(xiàng)時(shí)對(duì)遍歷次序比較敏感,所以這種特性在使用不同的查找次序時(shí)就很難再保持了。然而,這些問題并不是不可克服的(程序員可以預(yù)先靜態(tài)地為引導(dǎo)程序建立一顆前綴樹),如果性能在這里是主要因素,那么這種努力也是值得的。但是,由于性能在這里并不是主要問題,所以簡(jiǎn)單性才被作為最重要的因素體現(xiàn)出來。即使這樣,在類似的root_dev_names數(shù)組(19085行)中這個(gè)數(shù)組把硬件設(shè)備名的前綴映射到它們的主ID號(hào)上,開發(fā)者仍然可以簡(jiǎn)單地通過把比較常用的項(xiàng)(IDE和SCSI磁盤)放在不太常用的項(xiàng)(并口IDE CD)的前面以節(jié)省出一點(diǎn)性能。但是我在raw_params或cooked_params中并沒有發(fā)現(xiàn)與之類似的模式。另外一件需要注意的事是:現(xiàn)在你可以猜想一下為什么ro、rw和debug選項(xiàng)在parse_options中測(cè)試而不在這里測(cè)試,parse_options要檢測(cè)精確的匹配,但是checksetup只檢測(cè)前綴。作為一個(gè)特殊的情況,ro選項(xiàng)碰巧正好是root=(19553行)的前綴,這樣如果這三個(gè)選項(xiàng)彼此合并,就需要仔細(xì)處理了。這似乎仍然是一個(gè)相當(dāng)無力的原因??紤]一下noinitrd選項(xiàng)(19251行)。這是cooked_params的一個(gè)項(xiàng),因而只需要匹配前綴,而且與之相關(guān)聯(lián)的設(shè)置函數(shù)(no_initrd,19902行)將忽略所有可能已經(jīng)傳遞給它們的參數(shù)這正像ro、rw和debug被包含在cooked_params中時(shí)所可能進(jìn)行的工作一樣。19632:這個(gè)循環(huán)為cooked_params數(shù)組的處理工作和前面一個(gè)循環(huán)為raw_params數(shù)組的處理工作相同。這兩個(gè)循環(huán)(當(dāng)然不包括循環(huán)使用的數(shù)組)間的唯一區(qū)別是本循環(huán)在調(diào)用設(shè)置函數(shù)之前,使用get_options(19062行)處理line中=sign后面的部分。簡(jiǎn)單地說,get_options使用10個(gè)負(fù)整數(shù)填充ints1到s0中是ints中使用元素的個(gè)數(shù)也就是,它記錄了存儲(chǔ)在ints中的ints get_options數(shù)量。接著這個(gè)數(shù)組將被傳遞給設(shè)置函數(shù),該設(shè)置函數(shù)則會(huì)按照自己喜歡的方式對(duì)該數(shù)組內(nèi)容進(jìn)行解釋。19640:返回0,說明line中所包含的內(nèi)核選項(xiàng)不能被函數(shù)理解。3. profile_setup19076:profile_setup是checksetup調(diào)用的設(shè)置函數(shù)的一個(gè)完美的例子:這個(gè)函數(shù)十分短小,使用ints參數(shù)處理了部分內(nèi)容。而且到目前為止你也應(yīng)該對(duì)它的目的有了一定了解。正如前面提到的一樣,用戶可以在啟動(dòng)的時(shí)候設(shè)置prof_shift的值這里正是它的實(shí)現(xiàn)方式。當(dāng)內(nèi)核啟動(dòng)過程提供profile=選項(xiàng)時(shí),就調(diào)用profile_setup函數(shù)。前綴字符串和函數(shù)在19235行被聯(lián)系在一起。注意這是在cooked_params中,因此profile_setup取得的是處理過的參數(shù)。19079:如果參數(shù)中存在profile=的形式,就使用profile=后面的第一個(gè)數(shù)字作為prof_shift的新值。選項(xiàng)給出的其他參數(shù)都被簡(jiǎn)單地忽略了。19081:如果給出了profile=選項(xiàng),但是沒有為它提供參數(shù),prof_shift的缺省值就是2。這個(gè)缺省值有些奇怪,因?yàn)槲覀円呀?jīng)知道,這意味著使用四分之一的內(nèi)核可用內(nèi)存來配置其余部分這是一個(gè)很大的開銷。但是另一方面,使用這些內(nèi)存有助于更精確地定位問題熱點(diǎn)只有很少的幾條指令存在不確定性,這樣應(yīng)該比較容易地把問題限制在一兩行源程序代碼內(nèi)。那張圖也并不是像我所畫的那樣簡(jiǎn)單:因?yàn)閳D中只描述了內(nèi)核代碼,這種開銷還不到內(nèi)核所有內(nèi)存空間的25%,但是對(duì)于所覆蓋的代碼量來說卻并不止25%。4.3 initinit從許多方面看都是一個(gè)非常特殊的進(jìn)程。這是內(nèi)核運(yùn)行的第一個(gè)用戶進(jìn)程,它要負(fù)責(zé)觸發(fā)其他必需的進(jìn)程以使系統(tǒng)作為一個(gè)整體進(jìn)入可用的狀態(tài)。這些工作由/etc/inittab文件控制,通常包括設(shè)置getty進(jìn)程以接受用戶登錄,建立網(wǎng)絡(luò)服務(wù),例如FTP和HTTP守護(hù)進(jìn)程,等等。如果沒有這些進(jìn)程,用戶就不可能完成很多工作,這樣成功啟動(dòng)內(nèi)核就顯得沒有多大意義了。這種設(shè)計(jì)的另外一個(gè)主要的副作用是init是系統(tǒng)中所有進(jìn)程的祖先。init產(chǎn)生getty進(jìn)程,getty進(jìn)程產(chǎn)生login進(jìn)程,login進(jìn)程產(chǎn)生你自己的shell,使用自己的shell,可以產(chǎn)生每一個(gè)你運(yùn)行的進(jìn)程。在所有的結(jié)果中,這有助于確保內(nèi)核進(jìn)程表中的所有項(xiàng)最終都能夠得到處理。進(jìn)程結(jié)束以后將其清除(回收)的工作首先應(yīng)由其父進(jìn)程完成;如果父進(jìn)程已經(jīng)退出,那么祖父進(jìn)程就要擔(dān)負(fù)起這種責(zé)任;如果祖父進(jìn)程已經(jīng)退出,那么曾祖父進(jìn)程就要擔(dān)負(fù)起這種責(zé)任,周而復(fù)始。通過這種方式,從不退出的init進(jìn)程就可能要負(fù)責(zé)回收其他進(jìn)程。因此,為了確保這些重要的工作都能正確執(zhí)行,內(nèi)核初始化進(jìn)程所需要做的最后一步工作就是創(chuàng)建init進(jìn)程,接下來就加以描述。init20044:unused參數(shù)來源于該函數(shù)的非常規(guī)調(diào)用。init函數(shù)不要和init進(jìn)程搞混了,后者是它隨后要?jiǎng)?chuàng)建的作為內(nèi)核線程開始生命周期,一個(gè)作為內(nèi)核的一部分運(yùn)行的進(jìn)程(如果你編寫過多線程的程序,這里的內(nèi)核線程可能會(huì)同你所已經(jīng)知道的線程意義有所不同在那種意義下,它不是一個(gè)內(nèi)核線程)。實(shí)際上,init函數(shù)就像是新進(jìn)程使用的剝離出來了的main函數(shù),unused參數(shù)是一個(gè)獨(dú)立的指針,其值指向?yàn)榻o定進(jìn)程所提供的信息這比通常使用argc、argv和envp參數(shù)傳遞的信息要少得多。init函數(shù)碰巧不需要額外的信息,這個(gè)參數(shù)命名為unused,就是要強(qiáng)調(diào)這一點(diǎn)。為了確保在這一點(diǎn)上你不會(huì)產(chǎn)生困惑,我們?cè)谶@里再對(duì)整個(gè)機(jī)制進(jìn)行扼要重復(fù):init函數(shù)是內(nèi)核的一部分;它在內(nèi)核中作為內(nèi)核的一個(gè)獨(dú)立的執(zhí)行部分運(yùn)行;也就是說,無論從哪個(gè)方面看它都是內(nèi)核代碼。但是,init進(jìn)程就不是這樣了。在某些方面,init進(jìn)程是一個(gè)特殊的進(jìn)程,但是不屬于內(nèi)核本身;其代碼存儲(chǔ)在磁盤上單獨(dú)的可執(zhí)行映像中,這和其他程序一樣。因?yàn)閕nit函數(shù)后來產(chǎn)生init進(jìn)程,而它自己又恰好作為進(jìn)程運(yùn)行,這樣就很容易產(chǎn)生混淆。因?yàn)閕dle進(jìn)程已經(jīng)占據(jù)了進(jìn)程ID號(hào)(PID)0,init(當(dāng)然是init)就被賦值為下一個(gè)可用的PID,也就是1(進(jìn)程ID在第7章中討論)。內(nèi)核重復(fù)假定PID為1的進(jìn)程是init,因此這種特性在
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 統(tǒng)計(jì)學(xué)公式應(yīng)用技巧試題及答案
- 食品質(zhì)檢員日常工作技能要求試題及答案
- 商業(yè)分析師選拔試題及答案
- 2025個(gè)體餐館雇傭合同范本
- 2025《管道鋪設(shè)合同》
- 2025企業(yè)員工宿舍租賃合同
- 殘疾人服務(wù)知識(shí)與技巧
- 2025企業(yè)員工競(jìng)業(yè)禁止合同
- 2025 與護(hù)工簽訂的合同范本
- 體育產(chǎn)業(yè)未來趨勢(shì)與市場(chǎng)潛力深度解析
- 華北電力大學(xué)丁肇豪:多主體數(shù)據(jù)中心算力-電力跨域協(xié)同優(yōu)化
- 科技公司費(fèi)用報(bào)銷制度及流程比較
- 2024年紹興諸暨市水務(wù)集團(tuán)有限公司招聘考試真題
- 2025年新版供電營(yíng)業(yè)規(guī)則考試題庫
- 2025年長(zhǎng)白山職業(yè)技術(shù)學(xué)院?jiǎn)握新殬I(yè)技能測(cè)試題庫帶答案
- 2025年公務(wù)員遴選考試公共基礎(chǔ)知識(shí)必考題庫170題及答案(四)
- 2024年內(nèi)蒙古呼和浩特市中考物理試題【含答案、解析】
- 辦公用品及設(shè)備采購產(chǎn)品手冊(cè)
- DL-T-1878-2018燃煤電廠儲(chǔ)煤場(chǎng)盤點(diǎn)導(dǎo)則
- 《扣件式鋼管腳手架安全技術(shù)規(guī)范》JGJ130-2023
- 超星爾雅學(xué)習(xí)通《時(shí)間管理》章節(jié)測(cè)試含答案
評(píng)論
0/150
提交評(píng)論