




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
7.1Linux簡(jiǎn)介7.2Linux進(jìn)程管理7.3進(jìn)程間的通訊機(jī)制7.4Linux存儲(chǔ)管理7.5Linux文件系統(tǒng)7.6Linux設(shè)備管理7.7小結(jié)習(xí)題
7.1.1Linux的發(fā)展過程
Linux的工作方式類似于UNIX,是免費(fèi)的,源代碼也是開放的,是符合標(biāo)準(zhǔn)規(guī)范的32位(在64位CPU上是64位)操作系統(tǒng)。Linux擁有現(xiàn)代操作系統(tǒng)所具有的功能,例如:真正的搶先式多任務(wù)處理;支持多用戶;提供內(nèi)存保護(hù)機(jī)制;支持虛擬內(nèi)存;支持對(duì)稱多處理SMP(SymmetricMultiprocessing);符合POSIX標(biāo)準(zhǔn);提供聯(lián)網(wǎng)功能以及大量的網(wǎng)絡(luò)應(yīng)用;是圖形用戶接口和桌面環(huán)境(實(shí)際上桌面環(huán)境并不只一個(gè));保證速度和穩(wěn)定性要求等。7.1Linux簡(jiǎn)介嚴(yán)格說來,Linux并不是一個(gè)完整的操作系統(tǒng)。當(dāng)我們?cè)诎惭b通常所說的Linux時(shí),我們實(shí)際安裝的是很多工具的集合。這些工具協(xié)同工作以組成一個(gè)功能強(qiáng)大的實(shí)用系統(tǒng)。Linux本身只是這個(gè)操作系統(tǒng)的內(nèi)核,是操作系統(tǒng)的心臟、靈魂、指揮中心。內(nèi)核執(zhí)行最底層任務(wù),保證系統(tǒng)正常運(yùn)行——協(xié)調(diào)多個(gè)并發(fā)進(jìn)程,管理進(jìn)程使用的內(nèi)存,使它們相互之間不產(chǎn)生沖突,滿足進(jìn)程訪問磁盤的請(qǐng)求,等等。
1.UNIX的簡(jiǎn)明歷史
UNIX是由AT&T貝爾實(shí)驗(yàn)室的KenThompson和DennisRitchie于1969年在一臺(tái)已經(jīng)廢棄了的PDP-7上開發(fā)的,它最初是一個(gè)用匯編語言寫成的單用戶操作系統(tǒng)。不久后在PDP-11上用C語言重新編寫了UNIX,而且UNIX以及UNIX上運(yùn)行的工具在AT&T里得到廣泛應(yīng)用。在1973年,Thompson和Ritchie在一個(gè)操作系統(tǒng)會(huì)議上就這個(gè)系統(tǒng)發(fā)表了一篇論文,該論文引起了學(xué)術(shù)界對(duì)UNIX系統(tǒng)的極大興趣。后來UNIX被廣泛流傳,首先是學(xué)術(shù)科研用戶,后來又?jǐn)U展到政府和商業(yè)用戶。伯克利(Berkeley)的加州大學(xué)是學(xué)術(shù)用戶中的一個(gè)。在這里,UNIX得到了計(jì)算機(jī)系統(tǒng)研究小組(CSRG)的廣泛使用,并且對(duì)它進(jìn)行了修改,從而產(chǎn)生了UNIX的一大系列——伯克利軟件開發(fā)(BSD)UNIX。除了AT&T所提供的UNIX系列之外,BSD是最有影響力的UNIX系列。BSD在UNIX中增加了很多顯著特性,例如TCP/IP網(wǎng)絡(luò),更好的用戶文件系統(tǒng)(UFS)等,
并且改進(jìn)了AT&T的內(nèi)存管理代碼。在用戶需求和用戶編程的促進(jìn)下,BSD風(fēng)格的UNIX一般要比AT&T的UNIX更具有創(chuàng)新性,而且改進(jìn)也更為迅速。多年以來,BSD版本的UNIX一直在學(xué)術(shù)環(huán)境中占據(jù)主導(dǎo)地位,但最終AT&T的UNIXSystemV版本則成為商業(yè)領(lǐng)域的主宰。SystemVUNIX吸收了BSD大多數(shù)重要的優(yōu)點(diǎn),并且增加了一些自己的優(yōu)勢(shì)。然而,BSD的進(jìn)一步改進(jìn)由外界開發(fā)者延續(xù)下來,到今天還在繼續(xù)進(jìn)行。正在進(jìn)行的UNIX系列開發(fā)中有幾個(gè)獨(dú)立的版本是直接起源于BSD4.4。
由于UNIX主要使用C語言來編寫,這就使得它相對(duì)比較容易地移植到新的機(jī)器上,它的簡(jiǎn)單性也使其相對(duì)比較容易重新設(shè)計(jì)與開發(fā)。UNIX的這些特點(diǎn)大受商業(yè)界硬件供應(yīng)商的歡迎。版本混亂的狀態(tài)促進(jìn)了標(biāo)準(zhǔn)化工作的進(jìn)行。其中最主要的就是POSIX系列標(biāo)準(zhǔn),它定義了一套標(biāo)準(zhǔn)的操作系統(tǒng)接口和工具。從理論上說,POSIX標(biāo)準(zhǔn)代碼很容易移植到任何遵守POS
IX標(biāo)準(zhǔn)的操作系統(tǒng)中,而且嚴(yán)格的POSIX測(cè)試已經(jīng)把這種理論上的可移植性轉(zhuǎn)化為現(xiàn)實(shí)。直到今天,幾乎所有的正式操作系統(tǒng)都以支持POSIX標(biāo)準(zhǔn)為目標(biāo)。
2.Linux的發(fā)展
當(dāng)前流行的軟件按其提供方式可分為三種模式:商業(yè)軟件、共享軟件和自由軟件。自由軟件是由開發(fā)者提供軟件的全部源代碼,任何用戶都可以自由使用、拷貝、查詢、重用、修改甚至是分發(fā)這份軟件,完全沒有軟件使用協(xié)議的限制。1984年,Stallman組織開發(fā)了一個(gè)完全基于自由軟件體系計(jì)劃(GNU),并擬定了一份普通公共許可(GPL)。Linux從產(chǎn)生到發(fā)展一直遵循的是“自由軟件”思想。在GNU發(fā)展的中期,也就是1991年,一位名叫LinusTorvalds的芬蘭大學(xué)生想要了解Intel的新CPU——80386。他認(rèn)為比較好的學(xué)習(xí)方法是自己編寫一個(gè)操作系統(tǒng)的內(nèi)核。出于這種目的,加上他對(duì)當(dāng)時(shí)UNIX變種版本對(duì)于80386類機(jī)器的脆弱支持十分不滿,他決定要開發(fā)出一個(gè)全功能的、支持POSIX標(biāo)準(zhǔn)的、類UNIX的操作系統(tǒng)內(nèi)核,該系統(tǒng)吸收了BSD和SystemV的優(yōu)點(diǎn),同時(shí)摒棄了它們的缺點(diǎn)。Linus(雖然應(yīng)該稱他為Torvalds,但是所有人都稱他為L(zhǎng)inus)獨(dú)立地把這個(gè)內(nèi)核開發(fā)到0.02版,這個(gè)版本已經(jīng)可以運(yùn)行g(shù)cc、bash和很少的一些應(yīng)用程序。后來,他又開始在因特網(wǎng)上尋求廣泛的幫助。不到三年,Linus的UNIX,即Linux已經(jīng)升級(jí)到1.0版本。該軟件是按完全自由發(fā)布版權(quán)進(jìn)行發(fā)布的?,F(xiàn)在一些公司正在把內(nèi)核和一些應(yīng)用程序同安裝軟件打包在一起,生產(chǎn)出Linux的Distribution(發(fā)行版本)。目前的GNU/Linux已經(jīng)備受注目,得到了諸如Sun、IBM、SGI等公司的廣泛支持。
3.Linux開發(fā)過程
Linux是一款自由軟件,它可以免費(fèi)獲取以供學(xué)習(xí)研究。Linux之所以值得學(xué)習(xí)研究,是因?yàn)樗窍喈?dāng)優(yōu)秀的操作系統(tǒng)。它之所以十分優(yōu)秀基于三點(diǎn):
(1)它是基于天才的思想開發(fā)而成的。在學(xué)生時(shí)代就開始推動(dòng)整個(gè)系統(tǒng)開發(fā)的LinusTorvalds是一位天才,他的才能不僅展現(xiàn)在編程能力方面,而且組織技巧也相當(dāng)杰出。Linux的內(nèi)核是由世界上一些最優(yōu)秀的程序員開發(fā)并不斷完善的,他們通過Internet相互協(xié)作,而
開發(fā)出理想的操作系統(tǒng)。
(2)它的開發(fā)是基于一組優(yōu)秀的概念。UNIX是一個(gè)簡(jiǎn)單卻非常優(yōu)秀的模型。在Linux創(chuàng)建之前,UNIX已經(jīng)有20年的發(fā)展歷史。Linux從UNIX的各個(gè)流派中不斷吸取成功經(jīng)驗(yàn),模仿UNIX的優(yōu)點(diǎn),拋棄UNIX的缺點(diǎn),使Linux成為了UNIX系列中的佼佼者。
(3)它的開發(fā)過程是公開的。Linux最強(qiáng)大的生命力還在于其公開的開發(fā)過程。每個(gè)人都可以自由獲取內(nèi)核源程序,每個(gè)人都可以對(duì)源程序加以修改,而后他人也可以自由獲取你修改后的源程序。如果你發(fā)現(xiàn)了缺陷(bug),則可以對(duì)它進(jìn)行修正。如果你有什么最優(yōu)化或者新的創(chuàng)意,則也可以直接在系統(tǒng)中增加功能。當(dāng)發(fā)現(xiàn)一個(gè)安全漏洞后,你可以通過編程來彌補(bǔ)這個(gè)漏洞。由于你擁有直接訪問源代碼的能力,因此可以直接通過閱讀代碼來尋找缺陷,或是效率不高的代碼,或是安全漏洞,以防患于未然。
Linux這種獨(dú)特的自由流暢的開發(fā)模型已被命名為Bazaar(集市模型),它是相對(duì)于Cathedral(教堂模型)而言的。在Cathedral模型中,源程序代碼被鎖定在一個(gè)保密的小范圍內(nèi),只有開發(fā)者或市場(chǎng)認(rèn)為能夠發(fā)行一個(gè)新版本,這個(gè)新版本才會(huì)被推向市場(chǎng)。Bazaar開發(fā)模型通過重視實(shí)驗(yàn),征集并充分利用早期的反饋,集思廣義,開發(fā)出了更優(yōu)秀的軟件。為了確保這些無序的開發(fā)過程能夠有序地進(jìn)行,Linux采用了雙樹系統(tǒng),一棵是穩(wěn)定樹,另一棵是非穩(wěn)定樹或者開發(fā)樹。一些新特性、實(shí)驗(yàn)性改進(jìn)等都將首先在開發(fā)樹中進(jìn)行。如果在開發(fā)樹中所做的改進(jìn)也可以應(yīng)用于穩(wěn)定樹,那么在開發(fā)樹中經(jīng)過測(cè)試以后,在穩(wěn)定樹中將進(jìn)行相同的改進(jìn)。按照Linus的觀點(diǎn),一旦開發(fā)樹經(jīng)過了足夠的發(fā)展,開發(fā)樹就會(huì)成為新的穩(wěn)定樹,如此周而復(fù)始地進(jìn)行下去。源程序版本號(hào)的形式為x.y.z。對(duì)于穩(wěn)定樹來說,y是偶數(shù);對(duì)于開發(fā)樹來說,y比相應(yīng)的穩(wěn)定樹大1(因此是奇數(shù))。7.1.2Linux內(nèi)核結(jié)構(gòu)
1.內(nèi)核設(shè)計(jì)的目標(biāo)
Linux內(nèi)核的設(shè)計(jì)目標(biāo)是:清晰性、兼容性、可移植性、健壯性、安全性和速度。這些目標(biāo)有時(shí)是互補(bǔ)的,有時(shí)則是矛盾的,但是它們盡可能地保持在相互一致的狀態(tài)下。
(1)清晰性(Clarity)。內(nèi)核設(shè)計(jì)目標(biāo)是在保證速度和健壯性的前提下盡量清晰。在某種程度上,清晰性是健壯性的必要補(bǔ)充。但是清晰性和速度通常是一對(duì)矛盾。當(dāng)內(nèi)核中清晰性和速度要求不一致時(shí),通常都是以犧牲清晰性來保證速度的。
(2)兼容性(Compatibility)。Linux最初的編寫目的是為了實(shí)現(xiàn)一個(gè)完整的、與UNIX兼容的操作系統(tǒng)內(nèi)核,且以符合POSIX標(biāo)準(zhǔn)為目標(biāo)。兼容性表現(xiàn)在:
①兼容異種文件系統(tǒng)。它能夠支持很多文件系統(tǒng),例如ext2,ISO-9660,MS-DOS,網(wǎng)絡(luò)文件系統(tǒng)(NFS)等許多其它文件系統(tǒng)。
②提供對(duì)網(wǎng)絡(luò)的兼容。Linux不但提供對(duì)TCP/IP的支持,其內(nèi)核還支持其它許多網(wǎng)絡(luò)協(xié)議,包括AppleTalk協(xié)議,Novell的網(wǎng)絡(luò)協(xié)議,IP協(xié)議的新版本IPv6,以及其它一些不太出名的協(xié)議。③提供對(duì)硬件的兼容。Linux對(duì)不常見的顯卡,市場(chǎng)份額較小的網(wǎng)卡,非標(biāo)準(zhǔn)的CD-ROM接口和專用磁帶設(shè)備都有Linux的驅(qū)動(dòng)程序。
這些兼容性必須通過模塊度(Modularity)來實(shí)現(xiàn)。在可能的情況下,內(nèi)核只定義子系統(tǒng)的抽象接口,這種抽象接口可以通過任何方法來實(shí)現(xiàn)。例如,內(nèi)核對(duì)于新文件系統(tǒng)的支持將簡(jiǎn)化為對(duì)虛擬文件系統(tǒng)(VFS)接口代碼的實(shí)現(xiàn)。
(3)可移植性(Portability)。與硬件兼容性相關(guān)的設(shè)計(jì)目標(biāo)是可移植性,即在不同硬件平臺(tái)上運(yùn)行Linux的能力。系統(tǒng)可運(yùn)行在標(biāo)準(zhǔn)IBM兼容機(jī)上的Intelx86CPU,還可運(yùn)行在Alpha,ARM,Motorola69x0,MIPS,PowerPC,SPARC以及SPARC-64CPU上。Linux可以支持廣泛平臺(tái)的原因在于內(nèi)核把源程序代碼清晰地劃分為體系結(jié)構(gòu)無關(guān)部分和體系結(jié)構(gòu)相關(guān)部分。
(4)健壯性和安全性(RobustnessandSecurity)。Linux必須健壯、穩(wěn)定,系統(tǒng)自身應(yīng)該沒有任何缺陷,并且它還應(yīng)該可以保護(hù)進(jìn)程(用戶),以防止互相干擾。保證Linux健壯性和安全性的一個(gè)重要的因素是其開放的開發(fā)過程,它可以被看作是一種廣泛而嚴(yán)格的檢查。內(nèi)核中的每一行代碼、每一個(gè)改變都會(huì)很快由世界上數(shù)不清的程序員檢驗(yàn)。還有一些程序員專門負(fù)責(zé)尋找和報(bào)告潛在的缺陷。以前檢查中所沒有發(fā)現(xiàn)的缺陷可以通過這些人的努力來定位、修復(fù),而這種修復(fù)又合并進(jìn)主開發(fā)樹,以使所有的人都能夠受益。
(5)速度(Speed)。速度幾乎是最重要的衡量標(biāo)準(zhǔn),雖然其等級(jí)比健壯性、安全性和(有些時(shí)候的)兼容性的等級(jí)要低,然而它卻是代碼最直觀的幾個(gè)方面之一。Linux內(nèi)核代碼經(jīng)過了徹底的優(yōu)化,而最經(jīng)常使用的部分(例如調(diào)度程序)則是優(yōu)化工作的重點(diǎn)。
2.內(nèi)核體系結(jié)構(gòu)的設(shè)計(jì)方法
圖7.1是一種類UNIX操作系統(tǒng)的標(biāo)準(zhǔn)視圖,它表明所有期望具有平臺(tái)無關(guān)特性的操作系統(tǒng)其內(nèi)核應(yīng)有下面兩個(gè)特性:
(1)內(nèi)核將應(yīng)用程序和硬件分離開來;
(2)部分內(nèi)核是體系結(jié)構(gòu)和硬件特有的,而部分內(nèi)核則是可移植的。內(nèi)核通過把用戶應(yīng)用程序和硬件分離,使部分內(nèi)核將會(huì)因?yàn)榕c硬件的聯(lián)系而同其它內(nèi)核分離開來。通過這種分離,用戶的應(yīng)用程序和部分內(nèi)核都成為可移植的。雖然這通常并不能夠使得內(nèi)核本身更清楚,但是源程序代碼的體系結(jié)構(gòu)無關(guān)部分通常定義了與低層也就是體系結(jié)構(gòu)相關(guān)部分的接口,這樣,內(nèi)核向新的體系結(jié)構(gòu)的移植就成為可能。另外,用戶應(yīng)用程序的可移植性還可以通過標(biāo)準(zhǔn)C庫(libc)的協(xié)助來實(shí)現(xiàn)。應(yīng)用程序?qū)嶋H上不和內(nèi)核直接通訊,而只通過libc來實(shí)現(xiàn)。由于這種設(shè)計(jì),所有的用戶應(yīng)用程序,甚至大部分的C庫,都是通過體系結(jié)構(gòu)無關(guān)的方式和內(nèi)核通訊的。圖7.1內(nèi)核體系結(jié)構(gòu)基本結(jié)構(gòu)圖為了深入了解內(nèi)核的體系結(jié)構(gòu),圖7.2顯示了內(nèi)核概念化的一種可能方式。
進(jìn)程和內(nèi)核的交互通常需要通過如下步驟:
①用戶應(yīng)用程序調(diào)用系統(tǒng)調(diào)用,通常是使用libc。
②該調(diào)用被內(nèi)核的system_call函數(shù)截獲,此后該函數(shù)將調(diào)用請(qǐng)求轉(zhuǎn)發(fā)給另外的執(zhí)行請(qǐng)求的內(nèi)核函數(shù)。
③該函數(shù)隨即和相關(guān)內(nèi)部代碼模塊建立通訊,而這些模塊還可能需要和其它的代碼模塊或者底層硬件通訊。
④結(jié)果按照同樣的路徑依次返回。圖7.2詳細(xì)的內(nèi)核體系結(jié)構(gòu)圖
3.Linux系統(tǒng)內(nèi)核設(shè)計(jì)方法
操作系統(tǒng)內(nèi)核設(shè)計(jì)可以是微內(nèi)核方式,也可以是單內(nèi)核方式,這些術(shù)語定義如下:
(1)微內(nèi)核(MicrokernelKernel)。在微內(nèi)核中,大部分內(nèi)核都作為獨(dú)立的進(jìn)程在特權(quán)狀態(tài)下運(yùn)行,它們通過消息傳遞進(jìn)行通訊。在這種設(shè)計(jì)中,微內(nèi)核部分經(jīng)常只不過是一個(gè)消息轉(zhuǎn)發(fā)站:當(dāng)系統(tǒng)調(diào)用模塊要給文件系統(tǒng)模塊發(fā)送消息時(shí),消息直接通過內(nèi)核轉(zhuǎn)發(fā)。這種方式有助于實(shí)現(xiàn)模塊間的隔離。在一些微內(nèi)核的設(shè)計(jì)中,更多的功能也都被封裝在內(nèi)核中。但是最根本的思想還是要保持微內(nèi)核盡量小,這樣只需要把微內(nèi)核本身進(jìn)行移植就可以完成將整個(gè)內(nèi)核移植到新的平臺(tái)上。其它模塊都只依賴于微內(nèi)核或其它模塊,并不直接依賴于硬件。一般微內(nèi)核只提供4種最小的服務(wù):①進(jìn)程間通訊機(jī)制;
②某些內(nèi)存管理功能;
③少量的低層進(jìn)程管理和調(diào)度;
④低層輸入/輸出服務(wù)。
(2)單內(nèi)核(MonolithicKernel)。單內(nèi)核基本上是目前的集中式操作系統(tǒng),它是一個(gè)很大的進(jìn)程。它的內(nèi)部又可以被分為若干模塊(或者是層次或其它)。但是在運(yùn)行的時(shí)候,它是一個(gè)獨(dú)立的二進(jìn)制大映像。用戶是通過系統(tǒng)調(diào)用,而不是通過消息傳遞到達(dá)內(nèi)核的。在內(nèi)核中完成所需要的工作,然后內(nèi)核再將所要求的結(jié)果返回給用戶進(jìn)程。內(nèi)核中模塊間的通訊是通過直接調(diào)用其它模塊中的函數(shù)實(shí)現(xiàn)的。
Linux內(nèi)核基本上是使用單內(nèi)核,但它并不是一個(gè)純粹的集成內(nèi)核。它將微內(nèi)核的許多優(yōu)點(diǎn)引入到Linux的單內(nèi)核設(shè)計(jì)中。
4.內(nèi)核源程序目錄結(jié)構(gòu)
內(nèi)核源程序代碼一般安裝在/usr/src/linux目錄下。在該目錄下還有幾個(gè)其它目錄,每一個(gè)都代表一個(gè)特定的內(nèi)核功能性子集。
(1)documentation:該目錄下沒有內(nèi)核代碼,只有一套有用的文檔。
(2)arch:該目錄下的所有子目錄中都是與體系結(jié)構(gòu)相關(guān)的代碼。每種體系結(jié)構(gòu)特有的子目錄下又至少都包含三個(gè)子目錄;
①kernel:存放支持體系結(jié)構(gòu)特有的諸如信號(hào)量處理和SMP之類特征的實(shí)現(xiàn);
②lib:存放高速的體系結(jié)構(gòu)特有的一些通用函數(shù)的實(shí)現(xiàn);
③mm:存放體系結(jié)構(gòu)特有的內(nèi)存管理程序的實(shí)現(xiàn)。
除了這三個(gè)子目錄以外,大多數(shù)體系結(jié)構(gòu)在必要的情況下還都有一個(gè)boot子目錄,該目錄中包含有在這種平臺(tái)上啟動(dòng)內(nèi)核所使用的部分或全部平臺(tái)特有的代碼。這些啟動(dòng)代碼中的部分或全部也可以在平臺(tái)特有的內(nèi)核目錄下找到。
(3)drivers:該目錄是內(nèi)核中非常大的一塊。它包括顯卡、網(wǎng)卡、SCSI適配器、軟盤驅(qū)動(dòng)器、PCI設(shè)備和其它Linux支持的外圍設(shè)備的驅(qū)動(dòng)程序。
(4)fs:Linux支持的所有文件系統(tǒng)在fs目錄下都有一個(gè)對(duì)應(yīng)的子目錄。
(5)include:該目錄包含了Linux源程序樹中大部分的包含(.h)文件,它可分為:
①include/asm*/:arch的子目錄,每個(gè)目錄下的文件中包含了支持給定體系結(jié)構(gòu)所必需的預(yù)處理器宏和短小的內(nèi)聯(lián)函數(shù);
②include/linux/:包含內(nèi)核和用戶應(yīng)用程序請(qǐng)求特定內(nèi)核服務(wù)所使用的常量和數(shù)據(jù)結(jié)構(gòu),它在頭文件中定義;
③include/net/:供與網(wǎng)絡(luò)子系統(tǒng)有關(guān)的頭文件使用;
④include/scsi/:供與SCSI控制器和SCSI設(shè)備有關(guān)的頭文件使用;
⑤include/video/:供與顯卡和幀顯示緩存有關(guān)的頭文件使用。
(6)init:其較重要的一個(gè)文件是main.c,它包含了大部分協(xié)調(diào)內(nèi)核初始化的代碼。
(7)ipc:該目錄下的文件實(shí)現(xiàn)了SystemV的進(jìn)程間通訊(IPC)程序。
(8)kernel:這個(gè)目錄中包含了Linux中最重要的部分——實(shí)現(xiàn)平臺(tái)無關(guān)的基本功能。其中包括進(jìn)程調(diào)度(kernel/sched.c)、進(jìn)程創(chuàng)建和進(jìn)程撤銷的代碼(kernel/fork.c和kernel/exit.c)。
(9)lib:該目錄包含lib/inflate.c中的函數(shù),它能夠在系統(tǒng)啟動(dòng)時(shí)展開經(jīng)過壓縮的內(nèi)核。lib目錄下剩余的其它文件實(shí)現(xiàn)一個(gè)標(biāo)準(zhǔn)C庫的有用子集。
(10)mm:該目錄包含了體系結(jié)構(gòu)無關(guān)的內(nèi)存管理代碼,為每個(gè)平臺(tái)實(shí)現(xiàn)最低層的原語與體系結(jié)構(gòu)特有的內(nèi)存管理程序,它存儲(chǔ)在arch/platform/mm中。
(11)net:該目錄包含了Linux應(yīng)用的網(wǎng)絡(luò)協(xié)議代碼,例如AppleTalk,TCP/IP等。
(12)scripts:該目錄下沒有內(nèi)核代碼,它包含了用來配置內(nèi)核的腳本。當(dāng)運(yùn)行makemenuconfig或者makexconfig之類的命令配置內(nèi)核時(shí),用戶就是和位于該目錄下的腳本進(jìn)行交互的。7.1.3Linux運(yùn)行模式、地址空間與上下文
運(yùn)行Linux系統(tǒng)的計(jì)算機(jī)硬件至少需要提供兩種運(yùn)行模式:高優(yōu)先級(jí)的核心模式(特權(quán)模式)與低優(yōu)先級(jí)的用戶模式。核心運(yùn)行在高優(yōu)先級(jí),稱之為核心態(tài),其它外圍軟件包括Shell、編輯程序、X-Windows等都運(yùn)行在低優(yōu)先級(jí),稱之為用戶態(tài)。采用不同的執(zhí)行模式是為了系統(tǒng)保護(hù)。當(dāng)用戶進(jìn)程需要完成特權(quán)模式下才能完成的某些功能時(shí),必須嚴(yán)格按照系統(tǒng)調(diào)用提供的接口才能進(jìn)入特權(quán)模式,然后執(zhí)行調(diào)用所提供的有限的功能。每一種運(yùn)行態(tài)都有自己的堆棧,Linux中分為用戶棧和核心棧。采用特權(quán)模式進(jìn)行保護(hù)的根本目的是對(duì)地址空間的保護(hù),用戶進(jìn)程不能訪問所有的地址空間,只有通過系統(tǒng)調(diào)用才能進(jìn)入內(nèi)核,訪問受保護(hù)的那些地址空間的數(shù)據(jù)。另外,進(jìn)程與進(jìn)程之間的地址空間也不能隨便互訪。Linux通過虛存管理機(jī)制很好地實(shí)現(xiàn)了這種保護(hù)。
在虛存系統(tǒng)中,進(jìn)程所使用的地址不直接對(duì)應(yīng)物理的存儲(chǔ)單元,每個(gè)進(jìn)程都有自己的虛擬地址空間,對(duì)虛擬地址空間的引用通過地址變換機(jī)制轉(zhuǎn)換成物理地址的引用。虛擬地址空間分為兩部分:用戶空間和系統(tǒng)空間。在用戶模式下只能訪問用戶空間,而在核心模式下可以訪問用戶空間和系統(tǒng)空間。一個(gè)進(jìn)程的上下文可以分為三個(gè)部分:用戶級(jí)上下文、寄存器上下文以及系統(tǒng)級(jí)上下文。用戶級(jí)上下文有:正文、數(shù)據(jù)、用戶棧及共享存儲(chǔ)區(qū)。寄存器上下文有:程序計(jì)數(shù)器PC(即CPU將執(zhí)行的下條指令地址)、處理機(jī)狀態(tài)寄存器、棧指針、通用寄存器。系統(tǒng)級(jí)上下文有:進(jìn)程表結(jié)構(gòu)task_struct、存儲(chǔ)表及頁表和核心棧等。全部的上下文信息組成了一個(gè)進(jìn)程的運(yùn)行環(huán)境。當(dāng)發(fā)生進(jìn)程調(diào)度時(shí),必須對(duì)全部上下文信息進(jìn)行切換,新調(diào)度的進(jìn)程才能運(yùn)行。進(jìn)程就是上下文集合的一個(gè)抽象概念。
Linux和其它UNIX變種一樣,是一個(gè)多用戶操作系統(tǒng)。支持分時(shí)處理和“軟”實(shí)時(shí)處理。進(jìn)程具有獨(dú)立的權(quán)限與職責(zé)。如果系統(tǒng)中某個(gè)進(jìn)程崩潰,它不會(huì)影響到其余的進(jìn)程。Intel版本的Linux利用其體系結(jié)構(gòu)的保護(hù)模式和特權(quán)級(jí)等特征,將進(jìn)程分為內(nèi)核態(tài)和用戶態(tài)兩種級(jí)別。中斷和系統(tǒng)調(diào)用是內(nèi)核向用戶提供服務(wù)的重要途徑。
Linux的進(jìn)程管理由進(jìn)程控制塊、進(jìn)程調(diào)度、進(jìn)程間通信等部分組成,它是Linux存儲(chǔ)管理、文件管理和設(shè)備管理的基礎(chǔ)。Linux系統(tǒng)中的進(jìn)程包括交互進(jìn)程、批處理進(jìn)程和守護(hù)進(jìn)程。7.2Linux進(jìn)程管理
Linux可執(zhí)行文件可以有許多格式,甚至是一個(gè)腳本文件。它支持最廣的格式是a.out和ELF。ELF(可執(zhí)行與可連接格式)是UNIX/Linux系統(tǒng)一種常用的文件格式,與其它ECOFF和
a.out文件格式相比,ELF的開銷稍大,但它靈活。ELF可執(zhí)行文件中包含可執(zhí)行代碼段和數(shù)據(jù)段。7.2.1Linux進(jìn)程控制塊結(jié)構(gòu)
Linux利用一個(gè)數(shù)據(jù)結(jié)構(gòu)task_struct來表示一個(gè)進(jìn)程,該結(jié)構(gòu)稱為進(jìn)程控制塊。所有task_struct結(jié)構(gòu)的指針形成一個(gè)數(shù)組task。這意味著系統(tǒng)中的最大進(jìn)程數(shù)目受task數(shù)組大小的限制,其缺省值一般為512。當(dāng)建立新進(jìn)程時(shí),Linux將為新進(jìn)程分配一個(gè)task_struct結(jié)構(gòu),然后將指針保存在task數(shù)組中。當(dāng)前運(yùn)行進(jìn)程的結(jié)構(gòu)用current指針來指示。雖然task_struct數(shù)據(jù)結(jié)構(gòu)龐大而復(fù)雜,但它主要有如下功能信息:
(1)狀態(tài)信息(State)。進(jìn)程在執(zhí)行過程中會(huì)根據(jù)環(huán)境來改變它的狀態(tài)信息。Linux進(jìn)程有以下幾種狀態(tài):
①運(yùn)行(Running):進(jìn)程處于運(yùn)行(它是系統(tǒng)的當(dāng)前進(jìn)程)或者準(zhǔn)備運(yùn)行(它在等待系統(tǒng)將CPU分配給它)狀態(tài)。
②等待(Waiting):進(jìn)程在等待某個(gè)事件或者某個(gè)資源。Linux將等待進(jìn)程分成可中斷與不可中斷兩類??芍袛嗟却M(jìn)程是可被信號(hào)中斷的進(jìn)程;不可中斷等待進(jìn)程是正在直接等待硬件狀態(tài)條件的進(jìn)程,并且在任何情況下都不能被中斷。③停止(Stopped):進(jìn)程處于停止?fàn)顟B(tài),通常由于接收到信號(hào)而停止。正在被調(diào)試的進(jìn)程可能處于停止?fàn)顟B(tài)。
④死亡(Zombie):由于某些原因進(jìn)程已終止,但在task數(shù)據(jù)中仍然保留task_struct結(jié)構(gòu)。處于這種狀態(tài)的進(jìn)程是死進(jìn)程。
進(jìn)程狀態(tài)之間的轉(zhuǎn)換如圖7.3所示。圖7.3進(jìn)程之間狀態(tài)轉(zhuǎn)換圖
(2)調(diào)度信息(SchedulingInformation)。除上述State信息外,主要包括policy(策略)、priority(優(yōu)先級(jí))、rt_priority(實(shí)時(shí)優(yōu)先級(jí))和counter(計(jì)數(shù))。調(diào)度程序利用這些信息完成進(jìn)程之間的切換。
(3)進(jìn)程標(biāo)識(shí)符(Identifiers)。系統(tǒng)中每個(gè)進(jìn)程都有惟一的進(jìn)程標(biāo)識(shí)符。標(biāo)識(shí)符是個(gè)數(shù)字,用來控制進(jìn)程對(duì)系統(tǒng)中文件和設(shè)備的存取權(quán)限。Linux系統(tǒng)中所有的文件都有所有者和被允許者的權(quán)限,這些權(quán)限描述了系統(tǒng)使用者對(duì)文件或者目錄的使用權(quán)?;镜臋?quán)限是讀、寫和可執(zhí)行,這些權(quán)限被分配給三類用戶:文件的所有者,屬于相同組的進(jìn)程以及系統(tǒng)中的其它進(jìn)程。每類用戶具有不同的權(quán)限,例如一個(gè)文件允許其擁有者讀寫,但是同組的只能讀而其它進(jìn)程不允許訪問。
Linux使用組將文件和目錄的訪問特權(quán)授予一組用戶,而不是單個(gè)用戶或者系統(tǒng)中所有進(jìn)程。一個(gè)進(jìn)程可以同時(shí)屬于多個(gè)組(最多為32個(gè)),這些組都被放在進(jìn)程的task_struct中的group數(shù)組中。只要某組進(jìn)程可以存取某個(gè)文件,則屬于此組的進(jìn)程對(duì)該文件都有相應(yīng)的訪問權(quán)限。task_struct結(jié)構(gòu)中有4對(duì)進(jìn)程和組標(biāo)識(shí)符:
①uid,gid:表示運(yùn)行進(jìn)程的用戶標(biāo)識(shí)符和組標(biāo)識(shí)符。②有效uid和有效gid:一般情況下它與進(jìn)程的uid和gid相同,但在其它用戶允許的情況下,可用系統(tǒng)調(diào)用setuid(setgid)將它改變?yōu)槠渌脩舻膗id(gid),以獲得對(duì)該用戶的文件進(jìn)行操作的權(quán)限。
③文件系統(tǒng)uid和gid:用于文件系統(tǒng)操作的合法性訪問權(quán)限。
④保留uid和gid:根據(jù)POSIX標(biāo)準(zhǔn)引入這兩個(gè)標(biāo)識(shí)符。
(4)進(jìn)程間通訊信息(InterProcessCommunication)。Linux支持經(jīng)典的UNIXIPC機(jī)制,如信號(hào)、管道和SYSTEMV中IPC機(jī)制,包括共享內(nèi)存、信號(hào)量和消息隊(duì)列。系統(tǒng)利用這些信息實(shí)現(xiàn)進(jìn)程間的通訊。
(5)進(jìn)程鏈信息(Links)。Linux系統(tǒng)中除了初始化進(jìn)程外,任一進(jìn)程都有一個(gè)父進(jìn)程。每個(gè)新進(jìn)程都是從父進(jìn)程中復(fù)制過來,或者從父進(jìn)程克隆而來的。每個(gè)進(jìn)程對(duì)應(yīng)的task_struct結(jié)構(gòu)中包含有指向其父進(jìn)程和兄弟進(jìn)程(具有相同父進(jìn)程的進(jìn)程)以及子進(jìn)程的指針。另外,系統(tǒng)中所有進(jìn)程都用一個(gè)雙向鏈表鏈接起來,而它們的根是init進(jìn)程的task_struct數(shù)據(jù)結(jié)構(gòu)。這個(gè)鏈表被Linux內(nèi)核用來尋找系統(tǒng)中的所有進(jìn)程。
(6)時(shí)間和定時(shí)器(TimesandTimers)。系統(tǒng)在這些字段中保存進(jìn)程的建立時(shí)間以及在其生命期中所花費(fèi)的CPU時(shí)間。這一時(shí)間記錄進(jìn)程在系統(tǒng)和用戶兩種模式下所花費(fèi)的時(shí)間。Linux也支持與進(jìn)程相關(guān)的interval定時(shí)器,當(dāng)定時(shí)器到,操作系統(tǒng)會(huì)向該進(jìn)程發(fā)送信號(hào)。
(7)文件系統(tǒng)信息(FileSystem)。進(jìn)程可以自由地打開或關(guān)閉文件,進(jìn)程的task_struct結(jié)構(gòu)中包含指向每個(gè)打開文件描述符的指針*file以及指向兩個(gè)VFSinode的指針*fs。每個(gè)VFSInode惟一地標(biāo)記文件中的一個(gè)目錄或者文件,同時(shí)還對(duì)底層文件系統(tǒng)提供統(tǒng)一的接口。這兩個(gè)指針分別指向進(jìn)程的根目錄和進(jìn)程的當(dāng)前目錄。這兩個(gè)VFSinode包含同一個(gè)count域,當(dāng)有多個(gè)進(jìn)程引用時(shí),它的值將增加。
(8)虛擬內(nèi)存(VirtualMemory)。多數(shù)進(jìn)程都有一些虛擬內(nèi)存(內(nèi)核線程和后臺(tái)進(jìn)程沒有),task_struct的數(shù)據(jù)成員mm指向關(guān)于存儲(chǔ)管理的mm_struc結(jié)構(gòu),其中包含了一個(gè)虛存隊(duì)列mmap指向由若干vm_area_struc描述的虛存段。7.2.2進(jìn)程調(diào)度算法和調(diào)度策略
Linux進(jìn)程調(diào)度由scheduler()執(zhí)行,其任務(wù)是在run_queue隊(duì)列中選出一個(gè)進(jìn)程投入運(yùn)行。調(diào)度程序必須選擇最迫切需要運(yùn)行而且可以執(zhí)行的進(jìn)程來執(zhí)行。Linux使用基于優(yōu)先級(jí)的簡(jiǎn)單調(diào)度算法來選擇下一個(gè)運(yùn)行進(jìn)程。當(dāng)選定了新進(jìn)程后,系統(tǒng)必須將當(dāng)前進(jìn)程的狀態(tài)、處理器中的寄存器以及上下文狀態(tài)保存到task_struct結(jié)構(gòu)中。同時(shí)它將重新設(shè)置新進(jìn)程的狀態(tài)并將系統(tǒng)控制權(quán)交給此進(jìn)程。為了將CPU時(shí)間合理地分配給系統(tǒng)中的每個(gè)可執(zhí)行進(jìn)程,調(diào)度管理程序必須將這些時(shí)間信息也保存在task_struct中。
系統(tǒng)中存在兩類Linux進(jìn)程:普通進(jìn)程與實(shí)時(shí)進(jìn)程。實(shí)時(shí)進(jìn)程的優(yōu)先級(jí)要高于其它進(jìn)程。如果一個(gè)實(shí)時(shí)進(jìn)程處于可執(zhí)行狀態(tài),它將先得到執(zhí)行。實(shí)時(shí)進(jìn)程又有兩種策略:時(shí)間片輪轉(zhuǎn)和先進(jìn)先出。在時(shí)間片輪轉(zhuǎn)策略中,每個(gè)可執(zhí)行實(shí)時(shí)進(jìn)程輪流執(zhí)行一個(gè)時(shí)間片,而在先進(jìn)先出策略中每個(gè)可執(zhí)行進(jìn)程按各自在運(yùn)行隊(duì)列中的順序執(zhí)行并且順序不能變化。
計(jì)數(shù)器(Counter)記錄允許進(jìn)程運(yùn)行時(shí)間的時(shí)間片。進(jìn)程首次運(yùn)行時(shí)時(shí)間片為進(jìn)程優(yōu)先級(jí)的數(shù)值,但它隨時(shí)間的變化而遞減。創(chuàng)建子進(jìn)程時(shí),其計(jì)數(shù)器值為父進(jìn)程當(dāng)前時(shí)間片的一半。
內(nèi)核調(diào)度管理程序可以在幾種情況下發(fā)生,如當(dāng)前進(jìn)程被放入等待隊(duì)列時(shí)發(fā)生,系統(tǒng)調(diào)用結(jié)束時(shí)發(fā)生,從系統(tǒng)模式返回用戶模式時(shí)發(fā)生。每次調(diào)度管理程序運(yùn)行時(shí)將執(zhí)行以下工作:
(1)處理內(nèi)核中的工作。調(diào)度程序運(yùn)行底層處理程序并處理調(diào)度任務(wù)隊(duì)列。
(2)處理當(dāng)前進(jìn)程。在選定其它進(jìn)程運(yùn)行之前必須對(duì)當(dāng)前進(jìn)程進(jìn)行一些處理。如果當(dāng)前進(jìn)程的調(diào)度策略是時(shí)間片輪轉(zhuǎn),則它被放回到運(yùn)行隊(duì)列;如果任務(wù)可中斷且從上次被調(diào)度后接收到了一個(gè)信號(hào),則它的狀態(tài)變?yōu)镽unning;如果當(dāng)前進(jìn)程超時(shí),則它的狀態(tài)變?yōu)镽unning;如果當(dāng)前進(jìn)程的狀態(tài)是Running,則狀態(tài)保持不變。那些既不處于Running狀態(tài)又不是可中斷的進(jìn)程將會(huì)從運(yùn)行隊(duì)列中刪除。這意味著調(diào)度程序選擇運(yùn)行進(jìn)程時(shí)不會(huì)將這些進(jìn)程考慮在內(nèi)。
(3)選擇進(jìn)程。調(diào)度程序在運(yùn)行隊(duì)列中選擇一個(gè)最迫切需要運(yùn)行的進(jìn)程。普通進(jìn)程的權(quán)值是它的Counter值,而實(shí)時(shí)進(jìn)程則是Counter值加上1000。如果運(yùn)行隊(duì)列中存在實(shí)時(shí)進(jìn)程,則將優(yōu)先運(yùn)行實(shí)時(shí)進(jìn)程。如果系統(tǒng)中存在幾個(gè)相同優(yōu)先級(jí)的進(jìn)程,這時(shí)當(dāng)前運(yùn)行進(jìn)程已經(jīng)用掉了一些時(shí)間片,因此它將處在不利位置(其Counter值已經(jīng)變小),這樣位于運(yùn)行隊(duì)列最前面的進(jìn)程將先運(yùn)行。在存在多個(gè)相同優(yōu)先級(jí)進(jìn)程的平衡系統(tǒng)中,每個(gè)進(jìn)程被依次執(zhí)行,這就是RoundRobin策略。然而,由于進(jìn)程經(jīng)常需要等待某些資源,因此它們的運(yùn)行順序也常發(fā)生變化。
(4)進(jìn)程交換。如果系統(tǒng)選擇其它進(jìn)程運(yùn)行,則必須將當(dāng)前進(jìn)程掛起,且開始執(zhí)行新的進(jìn)程。當(dāng)掛起一進(jìn)程時(shí),該進(jìn)程所涉及到的機(jī)器狀態(tài),包括程序計(jì)數(shù)器(PC)和CPU寄存器將保存在進(jìn)程的task_struct數(shù)據(jù)結(jié)構(gòu)中,而即將運(yùn)行的進(jìn)程的task_struct狀態(tài)將裝入到機(jī)器中。如果當(dāng)前進(jìn)程或即將運(yùn)行的進(jìn)程使用了虛擬內(nèi)存,則必須更新系統(tǒng)的內(nèi)存頁面頁表。
Linux系統(tǒng)能運(yùn)行在SMP(對(duì)稱多處理)機(jī)器上,它能夠在系統(tǒng)中的各CPU間進(jìn)行合理的負(fù)載平衡調(diào)度。在多處理器系統(tǒng)中,希望每個(gè)處理器總處于工作狀態(tài)。當(dāng)處理器上的當(dāng)前進(jìn)程用完它的時(shí)間片或者等待系統(tǒng)資源時(shí),各個(gè)處理器將獨(dú)立運(yùn)行調(diào)度管理器。SMP系統(tǒng)中不只一個(gè)idle(空閑)進(jìn)程。在單處理器系統(tǒng)中,idle進(jìn)程是task數(shù)組中的第一個(gè)任務(wù)。在SMP系統(tǒng)中每個(gè)CPU都有一個(gè)idle進(jìn)程,同時(shí)每個(gè)CPU都有一個(gè)當(dāng)前進(jìn)程。SMP系統(tǒng)必須跟蹤每個(gè)處理器中的idle進(jìn)程和當(dāng)前進(jìn)程。
在SMP系統(tǒng)中,每個(gè)進(jìn)程的task_struct結(jié)構(gòu)中包含著當(dāng)前運(yùn)行它的處理器的編號(hào)以及上次運(yùn)行時(shí)處理器的編號(hào)。Linux使用processor_mask來使得某個(gè)進(jìn)程只在一個(gè)或者幾個(gè)處理器上運(yùn)行。
Linux系統(tǒng)中每個(gè)進(jìn)程使用兩個(gè)數(shù)據(jù)結(jié)構(gòu)描述與文件系統(tǒng)有關(guān)的信息,如圖7.4所示。第一個(gè)是fs_struct,它保存了進(jìn)程本身與VFS的關(guān)系信息。其中root指向根目錄節(jié)點(diǎn);pwd指向當(dāng)前目錄節(jié)點(diǎn);umask給出新建文件的訪問模式,可以通過系統(tǒng)調(diào)用umask來改變其值;count是Linux的保留屬性。第二個(gè)是files_struct,它包含了進(jìn)程當(dāng)前所打開的文件的信息。files_struct最多可以包含256個(gè)文件數(shù)據(jù)結(jié)構(gòu),每一個(gè)files_struct都描述一個(gè)進(jìn)程正在使用的文件。文件目錄結(jié)構(gòu)中f_mode表示創(chuàng)建文件的方式;f_pos保存文件中下一次讀寫操作的開始位置;f_inode指向描述此文件的VFSinode;f_op指向一組可以對(duì)此文件進(jìn)行操作的函數(shù)入口地址指針數(shù)組。圖7.4文件系統(tǒng)的數(shù)據(jù)成員7.2.3進(jìn)程使用的文件
每當(dāng)打開一個(gè)文件時(shí),位于files_struct中的一個(gè)空閑文件指針用來指向新的文件結(jié)構(gòu)。Linux系統(tǒng)中,進(jìn)程在啟動(dòng)時(shí)至少就已打開三個(gè)文件,它們分別是標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出和標(biāo)準(zhǔn)錯(cuò)誤輸出,它們分別對(duì)應(yīng)文件描述符fd[0]、fd[1]和fd[2]。7.2.4進(jìn)程使用的虛擬內(nèi)存
進(jìn)程的虛擬內(nèi)存中包括進(jìn)程的可執(zhí)行代碼和數(shù)據(jù)。首先裝入進(jìn)程的程序映象,它包含可執(zhí)行代碼和數(shù)據(jù)。然后進(jìn)程分配處理過程需要的虛擬內(nèi)存空間,新分配的虛擬內(nèi)存必須連接到進(jìn)程已存在的虛擬內(nèi)存中才能使用。最后Linux可以使多個(gè)進(jìn)程同時(shí)使用共享庫。
來自共享庫的代碼和數(shù)據(jù)必須連接到進(jìn)程的虛擬地址空間。
Linux使用請(qǐng)求調(diào)頁技術(shù)來把進(jìn)程需要訪問的虛擬內(nèi)存頁裝入物理內(nèi)存中,而無需將所有代碼和數(shù)據(jù)直接調(diào)入物理內(nèi)存。內(nèi)核將修改進(jìn)程的內(nèi)存頁表,標(biāo)記出不在內(nèi)存中的虛擬內(nèi)存
頁,當(dāng)進(jìn)程試圖訪問不在物理內(nèi)存的虛擬內(nèi)存頁時(shí),系統(tǒng)硬件將產(chǎn)生缺頁中斷,并將控制權(quán)交給Linux內(nèi)核來處理此缺頁中斷。
Linux內(nèi)核需要管理所有的虛擬內(nèi)存地址,每個(gè)進(jìn)程虛擬內(nèi)存中的內(nèi)容在其task_struct結(jié)構(gòu)中mm指針指向的vm_area_struct結(jié)構(gòu)中描述,如圖7.5所示。圖7.5進(jìn)程的虛擬內(nèi)存為進(jìn)程創(chuàng)建新虛擬內(nèi)存區(qū)或處理頁面不在物理內(nèi)存缺頁中斷時(shí),Linux內(nèi)核重復(fù)使用進(jìn)程的vm_area_struct數(shù)據(jù)結(jié)構(gòu)。這樣快速查找vm_area_struct成為系統(tǒng)性能的關(guān)鍵。Linux把vm_area_struct數(shù)據(jù)結(jié)構(gòu)采用AVL(AdelsonVelskiiandLandis)樹結(jié)構(gòu)連接以加快查找速度。在這種連接中,每個(gè)vm_area_
struct結(jié)構(gòu)有一個(gè)左右指針指向該節(jié)點(diǎn)的左右節(jié)點(diǎn)。為了找到某個(gè)節(jié)點(diǎn),可以從樹的根節(jié)點(diǎn)開始從左右兩個(gè)方向同時(shí)查找,大大提高了查找速度。
當(dāng)進(jìn)程請(qǐng)求分配虛擬內(nèi)存時(shí),Linux并不直接分配物理內(nèi)存。它只是創(chuàng)建一個(gè)vm_area_struct結(jié)構(gòu)來描述此虛擬內(nèi)存,此結(jié)構(gòu)被連接到進(jìn)程的虛擬內(nèi)存鏈表中。當(dāng)進(jìn)程試圖對(duì)新分配的虛擬內(nèi)存進(jìn)行操作時(shí),系統(tǒng)將產(chǎn)生缺頁中斷。處理器會(huì)嘗試解析此虛擬地址,但是如果找不到對(duì)應(yīng)此虛擬地址的頁表表項(xiàng)時(shí),處理器將放棄解析并產(chǎn)生缺頁中斷異常,由Linux內(nèi)核來處理。Linux則查看此虛擬地址是否在當(dāng)前進(jìn)程的虛擬地址空間中。如果是,Linux會(huì)創(chuàng)建正確的頁表并為此進(jìn)程分配物理頁面,包含在此頁面中的代碼或數(shù)據(jù)可能需要從交換文件或者交換磁盤上讀出。然后進(jìn)程將從缺頁中斷處開始繼續(xù)執(zhí)行,由于物理內(nèi)存已經(jīng)存在,因此不會(huì)再產(chǎn)生頁面異常。7.2.5系統(tǒng)調(diào)用
Linux通過shell和X-Window為用戶提供交互界面,即Linux通過各種系統(tǒng)調(diào)用為應(yīng)用系統(tǒng)、進(jìn)程提供了編程接口。Linux系統(tǒng)調(diào)用的形式與POSIX兼容,也是一套C語言函數(shù)的集合。Linux系統(tǒng)調(diào)用的內(nèi)部實(shí)現(xiàn)方式與DOS相似,使用INT80H軟中斷調(diào)用進(jìn)入,再根據(jù)系統(tǒng)調(diào)用號(hào)分別進(jìn)入相應(yīng)的系統(tǒng)調(diào)用函數(shù)。Linux系統(tǒng)調(diào)用函數(shù)名以“sys_”開頭,后跟該系統(tǒng)調(diào)用的名字,如系統(tǒng)調(diào)用fork()的相應(yīng)函數(shù)是sys_fork()。
Linux為每個(gè)系統(tǒng)調(diào)用規(guī)定了惟一的編號(hào),系統(tǒng)調(diào)用表sys_call_table存放所有系統(tǒng)調(diào)用函數(shù)的入口地址(見arch/i386/kernel/entry.S)。有了這張表,就很容易根據(jù)特定系統(tǒng)調(diào)用在表中的偏移量,找到對(duì)應(yīng)的系統(tǒng)調(diào)用函數(shù)的入口地址。
系統(tǒng)調(diào)用發(fā)生在用戶進(jìn)程通過調(diào)用指定函數(shù)(例如open)以請(qǐng)求內(nèi)核提供服務(wù)的時(shí)候。這時(shí),用戶進(jìn)程被暫時(shí)掛起,內(nèi)核檢驗(yàn)用戶請(qǐng)求,嘗試執(zhí)行,并把結(jié)果反饋給用戶進(jìn)程。系統(tǒng)調(diào)用負(fù)責(zé)保護(hù)對(duì)內(nèi)核所管理的資源的訪問,系統(tǒng)調(diào)用中主要有如下幾個(gè)大類:處理I/O請(qǐng)求(open,close,read,write,poll等),進(jìn)程操作(fork,execve,kill等),時(shí)間管理(time,settimeofday等)以及內(nèi)存管理(mmap,brk等)。幾乎所有的系統(tǒng)調(diào)用都可以歸入這幾類中。然而,從根本上來說,Linux系統(tǒng)調(diào)用在實(shí)現(xiàn)上不同于一般系統(tǒng)調(diào)用的實(shí)現(xiàn)。在Linux中,C庫中對(duì)于一些系統(tǒng)調(diào)用的實(shí)現(xiàn)是建立在其它系統(tǒng)調(diào)用的基礎(chǔ)之上的。例如,waitpid
是通過簡(jiǎn)單調(diào)用wait4實(shí)現(xiàn)的,但是它們兩個(gè)都是作為獨(dú)立的系統(tǒng)調(diào)用說明的。其它的傳統(tǒng)系統(tǒng)調(diào)用,如sigmask和ftime是由C庫而不是由Linux內(nèi)核本身實(shí)現(xiàn)的,即使不是全部,至少大部分是如此。從應(yīng)用程序的觀點(diǎn)來看,系統(tǒng)調(diào)用和其它的函數(shù)調(diào)用一樣。真正的系統(tǒng)調(diào)用至少包括用戶進(jìn)程對(duì)部分內(nèi)核代碼的調(diào)用。系統(tǒng)調(diào)用必須返回int的值,并且也只能返回int的值。為了方便起見,返回值如果為0或者為正,就說明調(diào)用成功;為負(fù),則說明發(fā)生了錯(cuò)誤。在最近的內(nèi)核版本中,系統(tǒng)調(diào)用
偶爾返回負(fù)值也不一定表示錯(cuò)誤了。在目前的幾個(gè)系統(tǒng)調(diào)用中(例如lseek),即使結(jié)果正確也會(huì)返回一個(gè)很大的負(fù)值。目前,錯(cuò)誤返回值是在-1到-4095范圍之內(nèi)。標(biāo)準(zhǔn)C庫實(shí)現(xiàn)能夠以更加成熟和高級(jí)的方式解釋系統(tǒng)調(diào)用的返回值;當(dāng)返回值為負(fù)時(shí),內(nèi)核本身就不用再做任何特殊的處理了。系統(tǒng)調(diào)用的激活有兩種方法:system_call函數(shù)和lcall7調(diào)用門(CallGate)。syscall函數(shù)是通過調(diào)用lcall7實(shí)現(xiàn)的(至少在x86平臺(tái)上是如此。因此,它并不是一個(gè)特有的方法)。
請(qǐng)注意:系統(tǒng)調(diào)用本身并不關(guān)心它們是由system_call還是由lcall7激活的。這種把系統(tǒng)調(diào)用和其實(shí)現(xiàn)方式區(qū)別開來的方法是十分精巧的。這樣,如果出于某種原因我們不得不增加一種激活系統(tǒng)調(diào)用的方法時(shí),也不必修改系統(tǒng)調(diào)用本身來支持這種方法。所有進(jìn)程部分時(shí)間運(yùn)行于用戶模式,部分時(shí)間運(yùn)行于系統(tǒng)模式。如何支持這些模式,底層硬件的實(shí)現(xiàn)各不相同,但是存在一種安全機(jī)制可以使它們?cè)谟脩裟J胶拖到y(tǒng)模式之間來回切換。用戶模式的權(quán)限比系統(tǒng)模式下的小得多。進(jìn)程是通過系統(tǒng)調(diào)用切換到系統(tǒng)模式繼續(xù)執(zhí)行的,此時(shí)內(nèi)核為進(jìn)程而執(zhí)行。7.2.6進(jìn)程的創(chuàng)建與終止
系統(tǒng)啟動(dòng)時(shí)總是處于內(nèi)核模式,此時(shí)只有一個(gè)進(jìn)程:初始化進(jìn)程,其標(biāo)識(shí)號(hào)為1,它負(fù)責(zé)完成系統(tǒng)的初始化設(shè)置任務(wù)以及執(zhí)行系統(tǒng)初始化程序(如/etc/init、/bin/init或/sbin/init中的一個(gè))。像所有進(jìn)程一樣,初始化進(jìn)程也有一個(gè)由堆棧、寄存器等表示的機(jī)器狀態(tài)。當(dāng)系統(tǒng)創(chuàng)建并運(yùn)行其它進(jìn)程時(shí),初始化進(jìn)程的信息將存儲(chǔ)在初始化進(jìn)程的task-struct結(jié)構(gòu)中。如果系統(tǒng)沒有任何事要做,調(diào)度管理程序?qū)⑦\(yùn)行idle進(jìn)程。idle進(jìn)程為惟一不是動(dòng)態(tài)分配task_struct的進(jìn)程,它的task_struct在內(nèi)核構(gòu)造
時(shí)靜態(tài)定義并且名字為init_task。
init程序以/etc/inittab為腳本文件來創(chuàng)建系統(tǒng)中的新進(jìn)程。新進(jìn)程還可以創(chuàng)建新進(jìn)程。創(chuàng)建新進(jìn)程是通過克隆老進(jìn)程或當(dāng)前進(jìn)程來創(chuàng)建的。新進(jìn)程的創(chuàng)建使用系統(tǒng)調(diào)用sys_fork()或sys_clone(),并且是在內(nèi)核模式下完成。在系統(tǒng)調(diào)用結(jié)束時(shí),系統(tǒng)從物理內(nèi)存中分配一個(gè)新的task_struct數(shù)據(jù)結(jié)構(gòu)和進(jìn)程堆棧,同時(shí)獲得一個(gè)惟一標(biāo)識(shí)此新進(jìn)程的標(biāo)識(shí)符(pid)。如果進(jìn)程是根據(jù)sys_clone()產(chǎn)生的,那么它的進(jìn)程標(biāo)識(shí)號(hào)就是當(dāng)前進(jìn)程的標(biāo)識(shí)號(hào),并且對(duì)它的task_struct中的fs、files、mm等指針并不進(jìn)行拷貝,而僅將當(dāng)前的count值加1,這樣只有當(dāng)父進(jìn)程中相關(guān)數(shù)據(jù)結(jié)構(gòu)成員的count值為0時(shí),Linux才會(huì)釋放這些數(shù)據(jù)結(jié)構(gòu)成員所占用的內(nèi)存空間。
當(dāng)父子進(jìn)程共享虛擬內(nèi)存時(shí),Linux使用“copyonwrite”技術(shù),只有當(dāng)父進(jìn)程或子進(jìn)程對(duì)虛存進(jìn)行寫操作時(shí),才給子進(jìn)程的mm指針?biāo)赶虻臄?shù)據(jù)結(jié)構(gòu)分配內(nèi)存,并將父進(jìn)程的mm指針?biāo)赶虻臄?shù)據(jù)結(jié)構(gòu)內(nèi)容拷貝到子進(jìn)程的mm指針上。
Linux支持大量的進(jìn)程間通訊(IPC)機(jī)制。除了信號(hào)和管道(包括命名管道)外,Linux還支持UNIXSYSTEMV中的IPC機(jī)制,即消息隊(duì)列、信號(hào)量和共享內(nèi)存。
7.3.1信號(hào)(Signal)
信號(hào)機(jī)制是Linux最基本的通訊機(jī)制。它可用來向一個(gè)或多個(gè)進(jìn)程發(fā)送異步事件信號(hào),傳送少量信息。7.3進(jìn)程間的通訊機(jī)制
Linux系統(tǒng)中定義一組信號(hào)類型,這些信號(hào)可以由內(nèi)核或者系統(tǒng)中其它具有適當(dāng)權(quán)限的進(jìn)程產(chǎn)生。對(duì)于收到信號(hào)的進(jìn)程,其task_struct中的signal屬性的某一位置位。使用kill命令(kill-l)可以列出系統(tǒng)中所有已經(jīng)定義的信號(hào),如:
1)SIGHUP
2)SIGINT
3)SIGQUIT
4)SIGILL
5)SIGTRAP
6)SIGIOT
7)SIGBUS
8)SIGFPE
9)SIGKILL
10)SIGUSR1
11)SIGSEGV
12)SIGUSR2
13)SIGPIPE
14)SIGALRM
15)SIGTERM
17)SIGCHLD
18)SIGCONT
19)SIGSTOP
20)SIGTSTP
21)SIGTTIN
22)SIGTTOU
23)SIGURG
24)SIGXCPU
25)SIGXFSZ
26)SIGVTALRM
27)SIGPROF
28)SIGWINCH
29)SIGIO
30)SIGPWR
進(jìn)程可以設(shè)置task_struct中的blocked屬性來屏蔽上述絕大部分的信號(hào)。但有兩個(gè)信號(hào)是不能屏蔽的,一個(gè)是引起進(jìn)程終止執(zhí)行的SIGSTOP信號(hào),另一個(gè)是引起進(jìn)程退出的SIGKILL信號(hào)。當(dāng)產(chǎn)生可屏蔽信號(hào)時(shí),此信號(hào)可以保持一直處于待處理狀態(tài),直到該屏蔽釋放為止。進(jìn)程可以選擇它們的具體方式來處理所產(chǎn)生的信號(hào),也可以使用系統(tǒng)的缺省方式處理信號(hào)。通過系統(tǒng)調(diào)用,進(jìn)程可以修改缺省的信號(hào)處理過程。對(duì)于同時(shí)到達(dá)兩個(gè)以上的信號(hào),Linux沒有規(guī)定處理的順序。只有內(nèi)核和超級(jí)用戶具有向其它進(jìn)程發(fā)送信號(hào)的權(quán)限。普通進(jìn)程只能向具有相同uid和gid的進(jìn)程或者在同一進(jìn)程組中的進(jìn)程發(fā)送信號(hào)。信號(hào)是通過設(shè)置task_struct結(jié)構(gòu)中signal字段里的某一位來產(chǎn)生的。如果進(jìn)程沒有屏蔽信號(hào)并且處于可中斷的等待狀態(tài),那么將喚醒進(jìn)程并進(jìn)入運(yùn)行狀態(tài),調(diào)度程序?qū)?huì)在下一次調(diào)度時(shí)考慮。
信號(hào)在產(chǎn)生時(shí)并不馬上送給進(jìn)程,它必須等待直到進(jìn)程再一次運(yùn)行時(shí)才交給它。每當(dāng)進(jìn)程從系統(tǒng)調(diào)用中退出時(shí),都會(huì)檢查該進(jìn)程的signal和blocked字段,看是否有可以立刻發(fā)送的非屏蔽信號(hào),如有則立即發(fā)送信號(hào)。如果信號(hào)的處理被設(shè)置為缺省,則系統(tǒng)內(nèi)核將會(huì)處理此信號(hào)。7.3.2管道(Pipe)
管道是UNIX系統(tǒng)傳統(tǒng)的進(jìn)程通訊技術(shù),Linux的管道是通過文件來實(shí)現(xiàn)的。當(dāng)進(jìn)程創(chuàng)建管道時(shí),內(nèi)核系統(tǒng)調(diào)用do_pipe()函數(shù)為這個(gè)管道提供兩個(gè)file_struct的文件描述符:一個(gè)用于寫操作,一個(gè)用于讀操作。兩個(gè)file_struct的f_inode屬性指向同一個(gè)VFSInode,Inode指向內(nèi)存的物理頁面,見圖7.6。在進(jìn)程向管道寫數(shù)據(jù)時(shí),數(shù)據(jù)被復(fù)制到共享物理頁面上。讀進(jìn)程從管道讀數(shù)據(jù)時(shí),實(shí)際上是從共享的物理頁面讀出,從而實(shí)現(xiàn)了進(jìn)程間的數(shù)據(jù)通訊。
Linux還支持命名管道,即FIFO管道。命名管道基本上與管道類似,它們之間的區(qū)別見表7-1。圖7.6管道操作示意圖7.3.3消息隊(duì)列
Linux支持UNIXSystemV的三種進(jìn)程間通訊機(jī)制:消息隊(duì)列、信號(hào)量以及共享內(nèi)存。SystemVIPC機(jī)制使用共同的授權(quán)方法。在Linux數(shù)據(jù)結(jié)構(gòu)中包含一個(gè)ipc_perm結(jié)構(gòu),它含有進(jìn)程擁有者和創(chuàng)建者的用戶與組的標(biāo)識(shí)符,此對(duì)象(擁有者,組及其它)的存取模式以及IPC目標(biāo)關(guān)鍵字。此關(guān)鍵字共有兩組:公有與私有。如關(guān)鍵字為公有,則系統(tǒng)中任何接受權(quán)限檢查的進(jìn)程都可以通過關(guān)鍵字得到引用標(biāo)識(shí)符。
消息隊(duì)列是進(jìn)程讀、寫信息的存儲(chǔ)空間。Linux維護(hù)著一個(gè)msgque消息隊(duì)列鏈表,其中每個(gè)元素指向一個(gè)描述消息隊(duì)列的msgid_ds結(jié)構(gòu)。當(dāng)創(chuàng)建新的消息隊(duì)列時(shí),系統(tǒng)將從系統(tǒng)內(nèi)存中分配一個(gè)msgid_ds結(jié)構(gòu),同時(shí)將其插入到數(shù)組中,如圖7.7所示。圖7.7Linux消息隊(duì)列每當(dāng)進(jìn)程希望對(duì)指定隊(duì)列進(jìn)行寫消息操作時(shí),調(diào)用系統(tǒng)調(diào)用sys_ipc,該進(jìn)程的標(biāo)識(shí)uid、gid首先與該隊(duì)列的msg_perm對(duì)應(yīng)屬性進(jìn)行比較。檢查通過后,將消息復(fù)制到msg結(jié)構(gòu)中,再掛接到消息隊(duì)列的末尾。由于Linux嚴(yán)格限制可寫入消息的個(gè)數(shù)和長(zhǎng)度,隊(duì)列中可能容納不下這個(gè)消息。此時(shí),該寫入進(jìn)程將被添加到這個(gè)消息的等待隊(duì)列中,同時(shí)調(diào)用進(jìn)程調(diào)度管理程序,選擇新的進(jìn)程運(yùn)行。當(dāng)有消息從此隊(duì)列中釋放時(shí),才喚醒該進(jìn)程。
讀消息進(jìn)程的工作過程與寫消息類似。7.3.4信號(hào)量
Linux和SystemV的信號(hào)量與普通信號(hào)量沒有什么不同,只是功能有所擴(kuò)充,它一次對(duì)一組信號(hào)(信號(hào)集)操作,每個(gè)操作除了wait、signal原語分別減1、加1外,還可以增加任意整數(shù)。其數(shù)據(jù)結(jié)構(gòu)如圖7.8所示。
Linux維護(hù)一個(gè)信號(hào)量集合的數(shù)組semary,該數(shù)據(jù)元素指向semid_ds結(jié)構(gòu)。此結(jié)構(gòu)管理著一個(gè)信號(hào)量集合sem_base、信號(hào)量集合的操作序列sem_pending以及撤銷操作的sem_undo序列。進(jìn)程終止時(shí),將消除所有被該進(jìn)程操作過的信號(hào)量的影響。圖7.8Linux信號(hào)量數(shù)據(jù)結(jié)構(gòu)7.3.5共享內(nèi)存
共享內(nèi)存機(jī)制允許多個(gè)進(jìn)程通過一塊共享的內(nèi)存來交換數(shù)據(jù)。因?yàn)檫M(jìn)程直接用虛擬地址訪問內(nèi)存中的數(shù)據(jù),其通訊效率通常比消息隊(duì)列、管道等方法高。共享內(nèi)存的虛擬內(nèi)存頁面出現(xiàn)在每個(gè)共享進(jìn)程頁表中,但此頁面并不一定位于所有共享進(jìn)程虛擬內(nèi)存的相同位置。和其它SystemVIPC對(duì)象的使用方法一樣,對(duì)共享內(nèi)存區(qū)域的訪問是通過關(guān)鍵字和訪問權(quán)限檢驗(yàn)來控制的。一旦內(nèi)存被共享后,則再不會(huì)檢驗(yàn)進(jìn)程對(duì)對(duì)象的使用方式。它依賴于其它機(jī)制,如使用SystemV信號(hào)量,來同步對(duì)共享內(nèi)存的訪問。7.4Linux存儲(chǔ)管理存儲(chǔ)管理子系統(tǒng)是操作系統(tǒng)中最重要的組成部分之一。由于人們所需要的內(nèi)存數(shù)目遠(yuǎn)遠(yuǎn)大于物理內(nèi)存,因此人們?cè)O(shè)計(jì)出了各種各樣的策略來解決此問題,其中最成功的是虛擬內(nèi)存技術(shù)。Linux采用“按需調(diào)頁”,支持三層式存儲(chǔ)管理策略,為每個(gè)用戶進(jìn)程提供4GB虛存空間,采用頗為獨(dú)特的頁面換出守護(hù)進(jìn)程kswapd,很好地解決了頁面置換問題。Linux還設(shè)計(jì)了swapcache和pagecache等緩沖區(qū)來提高操作效率,它使得系統(tǒng)中進(jìn)程競(jìng)爭(zhēng)有限物理內(nèi)存得到滿足。虛擬內(nèi)存技術(shù)不僅僅讓我們可以使用更多的內(nèi)存,它還提供了大地址空間、進(jìn)程保護(hù)、內(nèi)存映射、公平的物理內(nèi)存分配、共享虛擬內(nèi)存等功能。7.4.1虛擬內(nèi)存的實(shí)現(xiàn)機(jī)理
虛擬內(nèi)存系統(tǒng)中的所有地址都是虛擬地址而不是物理地址。通過操作系統(tǒng)所維護(hù)的一系列表格由處理器實(shí)現(xiàn)從虛擬地址到物理地址的轉(zhuǎn)換。為了使轉(zhuǎn)換更加簡(jiǎn)單,虛擬內(nèi)存與物理內(nèi)存都以頁面來組織。IntelX86系統(tǒng)上使用4KB頁面,每個(gè)頁面通過一個(gè)叫頁幀號(hào)(PFN)的數(shù)字來標(biāo)識(shí)。頁面模式下的虛擬地址由兩部分構(gòu)成:頁幀號(hào)和頁內(nèi)偏移量。處理器處理虛擬地址時(shí)必須完成地址分離工作。在頁表的幫助下,它將虛擬頁幀號(hào)轉(zhuǎn)換成物理頁幀號(hào),然后訪問物理頁面中的相應(yīng)偏移處。理論上每個(gè)頁表表項(xiàng)應(yīng)包含以下內(nèi)容:有效標(biāo)記(表示此頁表表項(xiàng)是有效的),頁表對(duì)應(yīng)的物理頁幀號(hào),訪問控制信息(描述此頁可進(jìn)行的操作)。為了將虛擬地址轉(zhuǎn)換為物理地址,處理器首先必須得到虛擬地址頁幀號(hào)及頁內(nèi)偏移。處理器使用虛擬頁幀號(hào)為索引來訪問處理器頁表,檢索頁表表項(xiàng)。如果在此位置的頁表表項(xiàng)有
效,則處理器將從此表項(xiàng)中得到物理頁幀號(hào)。如果此表項(xiàng)無效,則意味著處理器存取的是虛擬內(nèi)存中一個(gè)不存在的區(qū)域。在這種情況下,處理器是不能進(jìn)行地址轉(zhuǎn)換的,它必須將控制傳遞給操作系統(tǒng)來完成這個(gè)工作。這時(shí)處理器產(chǎn)生一個(gè)缺頁中斷而陷入操作系統(tǒng)內(nèi)核,這樣操作系統(tǒng)將得到有關(guān)無效虛擬地址的信息以及發(fā)生缺頁中斷的原因。7.4.280386體系結(jié)構(gòu)的存儲(chǔ)管理功能
80386的工作模式包括實(shí)地址模式和虛地址模式(又稱保護(hù)模式)。實(shí)地址模式只能尋址1MB的地址空間,不能使用分頁機(jī)制,不區(qū)分特權(quán)級(jí),分段功能也受到限制。而在保護(hù)模式下,分段機(jī)制得到加強(qiáng),虛地址空間可達(dá)16K段,每段大小可變,最大可達(dá)4GB,段可保護(hù),而且還提供段內(nèi)頁管理機(jī)制。80386虛地址模式同時(shí)使用了分段機(jī)制與分頁機(jī)制這兩級(jí)地址轉(zhuǎn)換機(jī)制來進(jìn)行地址轉(zhuǎn)換。第一級(jí)使用分段機(jī)制,把段地址和段內(nèi)偏移量的虛地址轉(zhuǎn)換為一個(gè)線性地址。第二級(jí)使用分頁機(jī)制,把線性地址轉(zhuǎn)換為物理地址,如圖7.9所示。80386的體系結(jié)構(gòu)為L(zhǎng)inux的虛存管理提供直接支持。圖7.9保護(hù)模式下的虛地址到物理地址的轉(zhuǎn)換
80386芯片內(nèi)部有一個(gè)32個(gè)表項(xiàng)的Cache,稱作TranslationLookasideBuffer(TLB),Cache中存放最近使用的頁面的32位線性地址和物理地址之間的對(duì)照表,從而加速轉(zhuǎn)換。每一個(gè)新的頁面都將按LRU算法替換其中的表項(xiàng)。進(jìn)程切換時(shí),TLB的所有32個(gè)表項(xiàng)都被新進(jìn)程的32表項(xiàng)所替換。7.4.3Linux分頁管理機(jī)制
1.訪問空間
在Linux中,每一個(gè)用戶都可以訪問4GB線性虛擬內(nèi)存空間。其中,0~3GB是用戶空間,用戶可以直接對(duì)它進(jìn)行訪問;3~4GB是內(nèi)核空間,存放內(nèi)核訪問的代碼和數(shù)據(jù),用戶態(tài)的程序不能訪問。所有進(jìn)程的3~4GB虛擬空間都是一樣的,有同樣的頁目錄項(xiàng),同樣的頁表,對(duì)應(yīng)到同樣的物理內(nèi)存段。
2.Linux的頁表設(shè)計(jì)
在i386系統(tǒng)中,虛擬地址空間的大小是4GB,每個(gè)頁表的大小為4KB。因此,全部的虛擬內(nèi)存空間劃分為1M頁。如果用一個(gè)頁表描述這種映射關(guān)系,那么一個(gè)映射表就要有1M個(gè)表項(xiàng),占用4MB內(nèi)存,這將會(huì)造成大量?jī)?nèi)存資源的浪費(fèi)。Linux為了避免硬件的不同細(xì)節(jié)影響內(nèi)核的實(shí)施,設(shè)置有三級(jí)頁表,而在i386系列CPU采用兩級(jí)頁表,將PGD和PMD兩個(gè)合為一個(gè),如下表所示。
3.存儲(chǔ)管理數(shù)據(jù)結(jié)構(gòu)mm_struct
新啟動(dòng)一進(jìn)程,Linux為其分配task_struct結(jié)構(gòu),其中內(nèi)含mm_struct結(jié)構(gòu),此結(jié)構(gòu)包含了以下用戶進(jìn)程中與存儲(chǔ)有關(guān)的信息:進(jìn)程頁目錄的起始地址(pgd),進(jìn)程代碼段的起始與結(jié)束,進(jìn)程數(shù)據(jù)段的起始與結(jié)束,調(diào)用參數(shù)區(qū)的起始地址/結(jié)束地址,進(jìn)程環(huán)境區(qū)的起始/結(jié)束地址,指向虛擬段的雙向鏈表,指向AVL樹指針,互斥信號(hào)量等。7.4.4空閑物理內(nèi)存空間管理
系統(tǒng)運(yùn)行過程中,經(jīng)常需要進(jìn)行物理內(nèi)存頁的分配與回收。例如,當(dāng)執(zhí)行程序時(shí),操作系統(tǒng)必須為其分配頁面。而當(dāng)進(jìn)程終止和卸載時(shí),則要釋放這些頁面。同時(shí)頁表本身也需要?jiǎng)討B(tài)地分配與釋放。物理頁面的分配和釋放機(jī)制及其相關(guān)數(shù)據(jù)結(jié)構(gòu)是虛擬內(nèi)存子系統(tǒng)的關(guān)鍵部分。
1.空閑塊的組織
Linux使用bitmap表以位示圖的方式記錄了所有物理內(nèi)存的空間情況。該表在系統(tǒng)初始化時(shí),由free_area_init()函數(shù)創(chuàng)建。
Linux的物理內(nèi)存分配采用鏈表和位示圖相結(jié)合的方法,如圖7.10所示。在Linux內(nèi)核定義了bitmap表,該表的每一項(xiàng)描述某一種頁塊的信息,表中第一個(gè)元素描述20個(gè)頁的信息,第二個(gè)元素描述以21個(gè)頁為一塊的頁塊信息,第三個(gè)元素描述以22個(gè)頁為一塊的頁塊信息,依此類推。所描述的塊都是2的次冪倍大小。free_area數(shù)組的每一項(xiàng)包含兩個(gè)元素:list和mem_map,list指向空閑頁塊的起始物理頁幀編號(hào),而map則是記錄這種頁塊組分配情況的位圖。圖7.10free_area數(shù)據(jù)結(jié)構(gòu)
2.空閑塊的分配
Linux使用buddy算法來有效地分配與釋放物理頁塊。按照上述的數(shù)據(jù)結(jié)構(gòu),Linux可以分配的內(nèi)存大小只能是1個(gè)頁的塊,2個(gè)頁的塊或4個(gè)頁的塊等等。在物理分配頁塊時(shí),Linux首先在free_area數(shù)組中尋找一個(gè)與請(qǐng)求大小相同的空閑頁塊。如果沒有所請(qǐng)求大小的空閑頁塊,則繼續(xù)搜索兩倍于請(qǐng)求大小的內(nèi)存塊。這個(gè)過程一直將持續(xù)到free_area被搜索完或找到滿足要求的最小頁塊為止。如果找到的空閑頁塊正好等于請(qǐng)求的塊長(zhǎng)時(shí),將它從中刪除。如果找到的頁面塊大于請(qǐng)求的頁塊時(shí),將空閑塊一分為二,前半部分插入free_area中前一條list鏈表中,取后半部分。若還大,則繼續(xù)對(duì)半分,留一半取一半,直至相等。在分配過程中要相應(yīng)調(diào)整bitmap表,將相應(yīng)位置“0”或置“1”。
3.空閑塊的回收
頁塊的分配會(huì)導(dǎo)致內(nèi)存碎片化,頁面回收則可將這些頁塊重新組合成單一大頁塊。當(dāng)頁塊被釋放時(shí),將檢查是否有相同大小的相鄰內(nèi)存塊存在。如果有,則將它們組合起來,形成一個(gè)大小為原來兩倍的新空閑塊。合并時(shí)要修改bitmap表的對(duì)應(yīng)位,從free_area的空閑鏈表中取下該相鄰的塊。每次組合完后,還要檢查是否可以繼續(xù)合并成更大的頁面,直至找不到空閑鄰居為止。最佳情況是系統(tǒng)的空閑頁塊的大小和允許分配的最大內(nèi)存一樣。7.4.5虛擬段的組織
映像執(zhí)行時(shí),可執(zhí)行映像的內(nèi)容必須裝入進(jìn)程的虛擬地址空間中,可執(zhí)行映像使用的共享庫同樣也裝入進(jìn)程虛擬地址空間中。然而,可執(zhí)行文件實(shí)際上并沒有調(diào)入物理內(nèi)存,而是僅
僅鏈接到進(jìn)程的虛擬內(nèi)存中。當(dāng)程序的其它部分運(yùn)行時(shí)引用到這部分時(shí)才把它們從磁盤上裝入內(nèi)存。這種將映像鏈接到進(jìn)程虛擬地址空間的過程稱為內(nèi)存映射。每個(gè)進(jìn)程的虛擬內(nèi)存用一個(gè)mm_struct結(jié)構(gòu)來表示。它包含當(dāng)前執(zhí)行映像的有關(guān)信息,以及指向vm_area_struct結(jié)構(gòu)的指針。如圖7.11所示,每個(gè)vm_area_struct數(shù)據(jù)結(jié)構(gòu)描述了虛擬內(nèi)存的起始與結(jié)束位置、進(jìn)程對(duì)內(nèi)存的存取權(quán)限以及對(duì)內(nèi)存的操作函數(shù)集。其中有一個(gè)負(fù)責(zé)處理進(jìn)程試圖訪問不在當(dāng)前物理內(nèi)存中的虛擬內(nèi)存(通過頁面失效)的函數(shù)。此函數(shù)為nopage,它在Linux試圖將可執(zhí)行映像的頁面調(diào)入內(nèi)存時(shí)使用。圖7.11虛擬內(nèi)存段數(shù)據(jù)結(jié)構(gòu)可執(zhí)行映像映射到進(jìn)程虛擬地址空間時(shí)將產(chǎn)生一組vm_area_struct數(shù)據(jù)結(jié)構(gòu)來描述虛擬內(nèi)存區(qū)域的起點(diǎn)與終點(diǎn),每一個(gè)vm_area_struct結(jié)構(gòu)代表可執(zhí)行映像的一部分,可能是存放可執(zhí)行代碼,也可能是初始化的變量或初始化的數(shù)據(jù)。Linux支持許多標(biāo)準(zhǔn)的虛擬內(nèi)存操作函數(shù),創(chuàng)建vm_area_struct數(shù)據(jù)結(jié)構(gòu)時(shí)有一組相應(yīng)的虛擬內(nèi)存操作函數(shù)與之對(duì)應(yīng)。7.4.6共享內(nèi)存
共享內(nèi)存允許不同的進(jìn)程通過一塊共享的內(nèi)存來交換數(shù)據(jù)。Linux中內(nèi)存共享是以頁共享的方式實(shí)現(xiàn)的,共享該頁的各進(jìn)程的頁表表項(xiàng)直接指向共享頁,見圖7.12。這種結(jié)構(gòu)不須設(shè)立共享頁表,節(jié)約內(nèi)存的占用,但效率低。因?yàn)楫?dāng)共享頁狀態(tài)發(fā)生變化時(shí),共享該頁的各進(jìn)程的頁表均需修改,要多次訪問頁表。UNIX的內(nèi)存共享是以頁表共享的形式出現(xiàn)的,設(shè)立一個(gè)臨時(shí)的公共頁表,各進(jìn)程原本指向共享頁表的表項(xiàng)改為指向公共頁表的表項(xiàng),公共頁表的表項(xiàng)再指向共享頁的地址。這種結(jié)構(gòu)執(zhí)行效率高,當(dāng)共享頁的狀態(tài)發(fā)生變化時(shí),只需修改公共頁的表項(xiàng)即可,只有一次頁表的訪問操作。圖7.12共享內(nèi)存結(jié)構(gòu)示意圖進(jìn)程訪問共享內(nèi)存的方式和訪問常規(guī)內(nèi)存的方式一樣,都經(jīng)由頁目錄和頁表,將虛擬地址翻譯成物理地址后,才可讀寫內(nèi)存。其管理方法也一樣,為每一個(gè)進(jìn)程的每一段共享內(nèi)存指派一個(gè)vm_area_struct結(jié)構(gòu)。此結(jié)構(gòu)和常規(guī)內(nèi)存的vm_area_struct連在一起。
進(jìn)程初次訪問共享內(nèi)存段時(shí),須先申請(qǐng)連接,通過perm檢查權(quán)限。一旦連接檢查通過,直至脫離連接,進(jìn)程對(duì)這種共享內(nèi)存的訪問就不再檢查了。
進(jìn)程可以自己選擇虛存空間哪一塊與該共享物理空間對(duì)應(yīng),或者由Linux指定足夠大的虛存空間與之對(duì)應(yīng)。申請(qǐng)的vm_area_struct結(jié)構(gòu)用于映射共享內(nèi)存段。進(jìn)程申請(qǐng)內(nèi)存共享前后,并沒有為該共享塊分配真正的物理頁面,它是在進(jìn)程第一次試圖訪問時(shí)才分配的。進(jìn)程訪問共享內(nèi)存時(shí),如內(nèi)存尚未分配,會(huì)產(chǎn)生缺頁中斷,缺頁中斷處理程序正確判斷缺頁中斷的原因,找出該進(jìn)程描述共享內(nèi)存的vm_area_struct(每個(gè)希望共享內(nèi)存的進(jìn)程都必須通過系統(tǒng)調(diào)用附加到虛擬內(nèi)存中,創(chuàng)建一個(gè)新的vm-area_struct)。檢查它所對(duì)應(yīng)的shmid_ds中shm_pages指示的頁表項(xiàng)目,看進(jìn)程是否引用了已經(jīng)存在的頁面。如果頁面已存在,則表示其它共享進(jìn)程已經(jīng)為該共享頁面申請(qǐng)了物理頁面,這時(shí)把該頁表項(xiàng)復(fù)制到進(jìn)程對(duì)應(yīng)的頁表中去。如果此共享內(nèi)存的頁面不存在,系統(tǒng)將為其分配一塊物理內(nèi)存,并同時(shí)為其創(chuàng)建一個(gè)新的頁表項(xiàng),則這個(gè)頁表項(xiàng)插入到進(jìn)程對(duì)應(yīng)的頁表的同時(shí),也插入到共享內(nèi)存的shmid_ds中。這樣,下一次如果其它進(jìn)程由于訪問該頁面產(chǎn)生缺頁中斷時(shí),缺頁中斷處理程序就不再分配新的物理內(nèi)存了。
進(jìn)程不再需要共享內(nèi)存時(shí),要脫離連接,即釋放該進(jìn)程對(duì)應(yīng)的vm_area_struct,頁表也將被更新。只要當(dāng)所有共享該內(nèi)存段的進(jìn)程都申請(qǐng)脫離連接,該共享內(nèi)存段的shmid_ds結(jié)構(gòu)及相應(yīng)的物理頁面才被釋放。
Linux可對(duì)虛擬段中任一部分加鎖和保護(hù),加鎖操作可以對(duì)進(jìn)程中指定一段虛擬空間加/解鎖,也可以對(duì)進(jìn)程中所有段加/解鎖。7.4.7請(qǐng)求換頁與頁面換入
當(dāng)可執(zhí)行映像映射到進(jìn)程的虛擬地址空間時(shí),它就可以開始運(yùn)行了。由于只有很少部分的映像調(diào)入內(nèi)存,因此很快就會(huì)發(fā)生對(duì)不在物理內(nèi)存中的虛擬內(nèi)存區(qū)的訪問。當(dāng)進(jìn)程訪問無有效頁表表項(xiàng)的虛擬地址時(shí),處理器將向Linux報(bào)告一個(gè)缺頁中斷。Linux必須找到出現(xiàn)缺頁的虛擬存儲(chǔ)段的vm_area_struct結(jié)構(gòu)。對(duì)vm_area_struct數(shù)據(jù)結(jié)構(gòu)的搜尋速度決定了處理缺頁中斷的效率,而所有vm_area_struct結(jié)構(gòu)是通過一種AVL(Adelson-VelskiiandLandis)樹結(jié)構(gòu)連在一起的。如果無法找到vm_area_struct與此失效虛擬地址的對(duì)應(yīng)關(guān)系,則系統(tǒng)認(rèn)為此進(jìn)程訪問了非法虛擬地址。這時(shí)Linux將向進(jìn)程發(fā)送SIGSEGV信號(hào),如果進(jìn)程沒有此信號(hào)的處理過程,則終止運(yùn)行。如果找到此對(duì)應(yīng)關(guān)系,Linux接下來檢查引起該缺頁中斷的訪存類型。如果進(jìn)程以非法方式訪問內(nèi)存,系統(tǒng)將產(chǎn)生內(nèi)存錯(cuò)誤的信號(hào)。如果Linux認(rèn)為缺頁中斷是合法的,那么它需要對(duì)這種情況進(jìn)行處理。首先Linux必須通過頁面對(duì)應(yīng)的頁表項(xiàng)判斷該頁是在交換空間中還是在可執(zhí)行映像中。頁面項(xiàng)是無效的但非空的,則缺頁是在交換空間中,否則頁面是一可執(zhí)行文件映像的一部分。
一般Linuxnopage函數(shù)被用來處理內(nèi)存映射可執(zhí)行映像,同時(shí)它使用頁面cache將請(qǐng)求的頁面調(diào)入到物理內(nèi)存中去。當(dāng)請(qǐng)求的頁面調(diào)入物理內(nèi)存時(shí),必須更新處理器頁表。更新這些表項(xiàng)必須進(jìn)行相關(guān)的硬件操作,特別是處理器使用TLB時(shí)。這樣當(dāng)處理完頁面失效后,進(jìn)程將從發(fā)生失效虛擬內(nèi)存訪問的位置重新開始運(yùn)行。7.4.8交換空間
Linux采用兩種方式保存換出的頁面。一種用整個(gè)塊設(shè)備,如硬盤的一個(gè)分區(qū),稱為交換設(shè)備。另一種用文件系統(tǒng)中固定長(zhǎng)度的文件,稱為交換文件。它們統(tǒng)稱為交換空間。不管是交換設(shè)備還是交換文件,其內(nèi)容格式都是一致的。前4096字節(jié)是一個(gè)以字符串“swap_space”結(jié)尾的位圖,位圖的每一位對(duì)應(yīng)一個(gè)交換空間的頁面,該位置位表示對(duì)應(yīng)的頁面可用于換頁操作。第4096字節(jié)之后是真正存放換出頁面空間。這樣每個(gè)交換空間最多可容納32697個(gè)頁面。
一個(gè)交換空間可能不夠用,Linux允許并行管理多個(gè)交換空間,缺省值是8個(gè)空間。7.4.9換出與丟棄頁面
當(dāng)系統(tǒng)中物理內(nèi)存減少時(shí),Linux內(nèi)存管理子系統(tǒng)必須釋放物理頁面。這個(gè)任務(wù)由內(nèi)核交換守護(hù)進(jìn)程(kswapd)來完成的。內(nèi)核交換守護(hù)進(jìn)程是一種特殊的內(nèi)核線程。它是沒有虛擬內(nèi)存的進(jìn)程,直接使用物理地址空間,運(yùn)行在內(nèi)核態(tài)下。該進(jìn)程的任務(wù)是將頁面交換到系統(tǒng)的交換空間(交換區(qū)或交換文件),保證系統(tǒng)中有足夠的空閑頁面來維持內(nèi)存管理系統(tǒng)高效運(yùn)行。在系統(tǒng)啟動(dòng)時(shí),此進(jìn)程由內(nèi)核的init進(jìn)程創(chuàng)建,然后每隔10ms周期性激活它。當(dāng)定時(shí)器到時(shí)后,內(nèi)核交換守護(hù)進(jìn)程將檢查系統(tǒng)中的空閑頁面數(shù)是否太少。它使用兩個(gè)變量:free_pages_high和free_pages_low,來判斷是否該釋放一些頁面。只要系統(tǒng)中的空閑頁面數(shù)大于free_pages_high,內(nèi)核交換守護(hù)進(jìn)程不做任何工作,它將睡眠到下一次定時(shí)器到時(shí)。在檢查中,內(nèi)核交換守護(hù)進(jìn)程將當(dāng)前寫到交換文件中的頁面數(shù)也計(jì)算在內(nèi)。如果系統(tǒng)中的空閑頁面數(shù)在free_pages_high甚至free_pages_low以下時(shí),內(nèi)核交換守護(hù)進(jìn)程將通過三個(gè)途徑來減少系統(tǒng)中使用的物理頁面的個(gè)數(shù):①減少緩沖區(qū)(BufferCache)與頁面Cache(PageCache)的大小。
②將SystemV的共享內(nèi)存頁面交換出去。
③換出或者丟棄進(jìn)程占用的頁面。
Linux并不會(huì)將選中進(jìn)程的所有頁面都交換出去,而只交換一小部分頁面。一個(gè)可執(zhí)行文件在執(zhí)行期間是不會(huì)改變的,這樣的頁面可以丟棄,當(dāng)再次執(zhí)行它時(shí),可以從對(duì)應(yīng)的軟件系統(tǒng)中調(diào)入。如果它所對(duì)應(yīng)的內(nèi)存被加鎖,則被加鎖的內(nèi)存頁面不能被交換或者丟棄。
Linux交換使用計(jì)齡換算法。每頁在mem_map_t結(jié)構(gòu)中有一個(gè)表示年齡的屬性,供kswapd決策該頁面是否值得換出。當(dāng)頁面未被使用,則會(huì)變老,交換守護(hù)進(jìn)程僅僅交換出那些老的頁面。其缺省的操作是:當(dāng)頁面被首次分配時(shí),其年齡初始值為3,每引用一次其年齡將加3,最大值為20。每當(dāng)內(nèi)核交換守護(hù)進(jìn)程要換出一頁時(shí),將它的年齡減1,直到0。這個(gè)缺省操作值是可以修改的。如果系統(tǒng)中空閑頁面數(shù)低于free_pages_low,則內(nèi)核交換守護(hù)進(jìn)程將在下次運(yùn)行之前釋放6個(gè)頁面,否則它只釋放3個(gè)。以上三種方法將依次使用直到系統(tǒng)釋放出足夠的空閑頁面。當(dāng)內(nèi)核交換守護(hù)進(jìn)程試圖釋放物理頁面時(shí),它將記錄使用的最后一種方法。下一次它會(huì)首先運(yùn)行上次最后成功的算法。
當(dāng)釋放出足夠頁面后,內(nèi)核交換守護(hù)進(jìn)程將再次睡眠到下次定時(shí)器到時(shí)。如果導(dǎo)致內(nèi)核交換守護(hù)進(jìn)程釋放頁面的原因是系統(tǒng)中的空閑頁面數(shù)小于free_pages_low,則它只睡眠平時(shí)的一半時(shí)間。一旦空閑頁面數(shù)大于free_pages_low,內(nèi)核交換守護(hù)進(jìn)程的睡眠時(shí)間又會(huì)延長(zhǎng)。7.4.10
溫馨提示
- 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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 有效管理時(shí)間的月度工作方案計(jì)劃
- 儀表知識(shí)溫度培訓(xùn)課件
- 第24課《唐詩三首》之《茅屋為秋風(fēng)所破歌》教學(xué)設(shè)計(jì) 2023-2024學(xué)年統(tǒng)編版語文八年級(jí)下冊(cè)
- 某婦產(chǎn)醫(yī)院品牌推廣部網(wǎng)絡(luò)推廣工作思路
- 2025年青海普通貨運(yùn)從業(yè)資格證模擬考試
- 2025年淮南駕駛資格證模擬考試
- 2025年杭州貨運(yùn)從業(yè)資格模擬考試
- 2025年上海貨運(yùn)從業(yè)資格證考試試題及答案
- 2025年德州c1貨運(yùn)從業(yè)資格證考試內(nèi)容
- 2025年陜西貨運(yùn)叢業(yè)資格證考試題目及答案
- 福晨河北科技發(fā)展有限公司年分裝500噸化學(xué)試劑建設(shè)項(xiàng)目環(huán)境影響報(bào)告表
- 地磁磁場(chǎng)的基本特征及應(yīng)用
- 國(guó)內(nèi)外鋼材牌號(hào)對(duì)照表
- 一年級(jí)下冊(cè)地方課程教案
- 有趣的仿生設(shè)計(jì)(課堂PPT)
- 第二章 航空飛行常見疾病
- 個(gè)體診所聘用醫(yī)師合同范本
- 航運(yùn)公司開展安全管理體系有效性
- 牛羊定點(diǎn)屠宰廠項(xiàng)目可行性研究報(bào)告-甲乙丙資信
- 妊娠糖尿病-楊慧霞.ppt
- 上海機(jī)場(chǎng)控制區(qū)通行證申請(qǐng)表(人員)
評(píng)論
0/150
提交評(píng)論