Linux的操作系統(tǒng)原理詳解
Linux的操作系統(tǒng)原理詳解
1.操作系統(tǒng)基本概念
操作系統(tǒng)是一個基本程序的集合,在這個集合中,最重要的程序稱為內(nèi)核(Kernel)。當(dāng)操作系統(tǒng)啟動時,內(nèi)核被裝載到 RAM中。內(nèi)核為操作系統(tǒng)提供了主要功能,一般把“內(nèi)核”作為“操作系統(tǒng)”的同義詞。
操作系統(tǒng)有兩個目標(biāo):
.與硬件交互:為硬件平臺上的低層可編程部件提供服務(wù)
.為用戶程序提供執(zhí)行環(huán)境
當(dāng)用戶程序想要使用硬件資源時,需要向操作系統(tǒng)發(fā)送請求;內(nèi)核對這個請求進(jìn)行評估,如果允許使用該硬件資源,則由內(nèi)核代表與相關(guān)硬件進(jìn)行交互。為了實現(xiàn)這種機制,操作系統(tǒng)依靠特殊的硬件機制來禁止用戶程序直接與硬件交互;CPU至少引入了兩種執(zhí)行模式:用戶程序的非特權(quán)模式 &內(nèi)核的特權(quán)模式;在 Unix中分別稱為用戶態(tài)(User Model)& 內(nèi)核態(tài)(Kernel Model)。
1.1多用戶系統(tǒng)
多用戶系統(tǒng)(Multiuser System)是指能夠并發(fā)且獨立地執(zhí)行分別屬于多個用戶的應(yīng)用程序的系統(tǒng)。
并發(fā)是多個應(yīng)用程序能同時處于活動狀態(tài)并且競爭各種資源,如 CPU,內(nèi)存,硬盤等。獨立是指每個應(yīng)用程序能夠執(zhí)行自己的任務(wù)而不需要考慮其他應(yīng)用程序的行為。
多用戶系統(tǒng)需要具備以下特點:
·用戶身份認(rèn)證機制
·應(yīng)用程序運行的保護機制:防止不同用戶程序之間的干擾
·分配給每個用戶的資源的記賬機制
上述安全機制的實現(xiàn)與 CPU特權(quán)模式相關(guān);Unix是多用戶系統(tǒng)
1.2用戶與組
在多用戶系統(tǒng)中,每個用戶在機器上都有私用空間,比如磁盤空間。
操作系統(tǒng)需要保證用戶空間的私有部分僅僅對其擁有者是可見的
每個用戶在操作系統(tǒng)中都有一個唯一標(biāo)識,叫做用戶標(biāo)識符(User ID);同時,為了與其他用戶有選擇地共享資料,每個用戶可以是一個或者多個用戶組的成員,組由用戶組標(biāo)識符唯一標(biāo)識(User Group ID)。
每個文件也與一個用戶組對應(yīng):比如同組用戶可以讀,其他用戶不可讀
Unix系統(tǒng)中存在一個 root用戶,操作系統(tǒng)不對其進(jìn)行進(jìn)行任何限制,root能夠訪問系統(tǒng)中的任何一個文件,干涉任意一個用戶程序。
1.3進(jìn)程
進(jìn)程(Process)是操作系統(tǒng)對正在運行程序的一個抽象。一個進(jìn)程可以看作“程序執(zhí)行的一個實例”或者“一個運行程序的執(zhí)行上下文”。
每個進(jìn)程都有一個地址空間(Address Space):允許進(jìn)程引用的內(nèi)存地址集合。
在多用戶系統(tǒng)中,多個進(jìn)程能夠并發(fā)執(zhí)行,并且能夠競爭系統(tǒng)資源;這種允許進(jìn)程并發(fā)活動的系統(tǒng)被稱為多道程序系統(tǒng)或者多處理系統(tǒng)。
進(jìn)程與程序之間的關(guān)系:幾個進(jìn)程能夠并發(fā)地執(zhí)行同一個程序,而一個進(jìn)程能夠順序執(zhí)行多個程序
在單處理器系統(tǒng)上,在某一個時刻只能有一個進(jìn)程占用 CPU;操作系統(tǒng)中的調(diào)度程序(Scheduler)用于協(xié)調(diào)進(jìn)程的執(zhí)行。在不同的操作系統(tǒng)中,進(jìn)程的執(zhí)行方式分為兩種:
·非搶占式:只有當(dāng)進(jìn)程自愿放棄 CPU時,調(diào)度程序才能被調(diào)用
·搶占式:CPU可以被其他進(jìn)程搶占;比如,操作系統(tǒng)記錄每個進(jìn)程占有 CPU的時間,并周期性地激活調(diào)度程序
Unix是具有搶占式進(jìn)程的多處理系統(tǒng)
Unix采用進(jìn)程/內(nèi)核模式。每個進(jìn)程都認(rèn)為自己是系統(tǒng)中的唯一進(jìn)程,獨占操作系統(tǒng)所提供的服務(wù)。當(dāng)進(jìn)程發(fā)出系統(tǒng)調(diào)用時,硬件就會把特權(quán)模式由用戶態(tài)切換到內(nèi)核態(tài),之后進(jìn)程以有限的目的開始一個內(nèi)核過程的執(zhí)行。當(dāng)請求調(diào)用結(jié)束,內(nèi)核過程迫使硬件返回到用戶態(tài),然后進(jìn)程從系統(tǒng)調(diào)用的下一條指令繼續(xù)執(zhí)行。
2. Unix文件系統(tǒng)概述
2.1文件
Unix文件是以字節(jié)序列組成的信息載體,內(nèi)核并不解釋文件的內(nèi)容。文件被組織成一個樹形結(jié)構(gòu)的命名空間中:
除了葉子節(jié)點外,其他節(jié)點都表示目錄名;目錄節(jié)點包含它下面的文件及目錄所有的信息。
文件名長度一般限制在 255個字符內(nèi);同一個目錄下的文件名不能相同
Unix進(jìn)程有一個當(dāng)前工作目錄,屬于進(jìn)程執(zhí)行上下文,用于標(biāo)識進(jìn)程所用的文件目錄。同時,進(jìn)程使用路徑名(Path Name)標(biāo)識特定的文件。
"."表示當(dāng)前工作目錄;“..”表示父目錄
2.2軟鏈接與硬鏈接
包含在目錄中的文件名就是一個文件的硬鏈接(Hard Link),簡稱鏈接。
在同一個目錄或者不同的目錄中,同一個文件可以有多個鏈接,因此對應(yīng)多個文件名。
一個文件可以對應(yīng)多個文件名,而一個文件名就是一個鏈接
$ ln P1 P2 #為由路徑 P1標(biāo)識的文件創(chuàng)建一個路徑名為 P2的硬鏈接
硬鏈接有兩個限制:
.不允許給目錄創(chuàng)建硬鏈接:會使得目錄樹變成環(huán)形圖,導(dǎo)致不能通過文件名定位文件
.只有在同一個文件系統(tǒng)中的文件之間才能創(chuàng)建鏈接:Unix系統(tǒng)中可能包含了多種文件系統(tǒng)
為了突破上面的兩個限制,引入了軟鏈接(Soft Link),也稱為符號鏈接。符號鏈接是短文件(軟鏈接也是文件),包含另一個文件的任意一個路徑名。路徑名可以指向任意文件系統(tǒng)的任意文件或者目錄,甚至可以指向一個不存在的文件。
$ ln -s P1 P2 #創(chuàng)建一個路徑名為 P2的軟鏈接,P2指向路徑名 P1;對 P2的引用都自動轉(zhuǎn)化為對 P1的引用
總結(jié):硬鏈接相當(dāng)于對源文件的直接引用,軟鏈接是對源文件的間接引用。
2.2文件類型
Unix文件類型分為:
·普通文件
·目錄
·符號鏈接
·面向塊的設(shè)備文件
·面向字符的設(shè)備文件
·管道 &命名管道
·套接字
前三種是基本的文件類型;設(shè)備文件與 IO設(shè)備及相關(guān)驅(qū)動程序有關(guān);管道與套接字是用于進(jìn)程間通信的特殊文件。
2.3文件描述符與索引節(jié)點
Unix文件的內(nèi)容與文件描述信息是分開存儲的:
.文件內(nèi)容是由字節(jié)序列組成,不包含任何控制信息,如文件長度等
.文件的描述信息存儲在索引節(jié)點(Index Node)中,每個文件都有自己的索引節(jié)點;文件系統(tǒng)用索引節(jié)點來標(biāo)識文件
索引節(jié)點中包含的信息有:
·文件類型
·與文件相關(guān)的硬鏈接個數(shù)
·以字節(jié)為單位的文件長度
·在文件系統(tǒng)中用于標(biāo)識文件的索引節(jié)點號
·文件擁有者的 UID
·文件的用戶組 ID
·訪問權(quán)限和文件模式
2.4文件操作的系統(tǒng)調(diào)用
當(dāng)用戶訪問文件內(nèi)容時,實際上是訪問存儲在硬件塊設(shè)備上的數(shù)據(jù)。由于處于用戶態(tài)的進(jìn)程不能直接與底層硬件交互,所以每次文件操作必須在內(nèi)核態(tài)下進(jìn)行。
2.4.1打開文件
fd = open(path, flag, mode); // flag指定打開文件的方式(讀,寫,追加)
該系統(tǒng)調(diào)用創(chuàng)建一個“打開文件”對象,并返回文件描述符。
其中,打開文件對象包括:
·文件操作的一些數(shù)據(jù)結(jié)構(gòu):表示文件當(dāng)前位置的 offset;指定文件打開方式的一組標(biāo)識
·進(jìn)程可以調(diào)用的一些內(nèi)核函數(shù)指針
文件描述符表示進(jìn)程與打開文件之間的交互,而打開的文件對象包含了與這種交互相關(guān)的數(shù)據(jù)。
同一個打開文件對象可以由同一個進(jìn)程的幾個文件描述符標(biāo)識
多個進(jìn)程同時打開一個文件時,文件系統(tǒng)會給每個進(jìn)程分配一個單獨的打開文件對象與單獨的文件描述符。
2.4.2訪問打開的文件
對于普通的 Unix文件,可以順序訪問,也可以隨機訪問;默認(rèn)是順序訪問。
內(nèi)核把文件指針存放在打開文件對象中
read()與write()是從文件指針的當(dāng)前位置開始操作;如果需要更新文件指針的值,必須顯示調(diào)用lseek()。
2.4.3關(guān)閉文件
res = close(fd);
該方法用于釋放與文件描述符相對應(yīng)的打開文件對象。
進(jìn)程終止時,內(nèi)核會關(guān)閉所有仍然打開的文件
2.4.4重命名與刪除文件
res = rename(oldPath, newPath); //更新了文件鏈接的名字
res = unlink(pathName); //減少文件鏈接數(shù),刪除了對應(yīng)的目錄項;當(dāng)鏈接數(shù)為 0時,文件才會被真正刪除
刪除與重命名文件時,并不需要打開文件。這兩個操作并沒有對文件的內(nèi)容進(jìn)行更新,而是對目錄的內(nèi)容進(jìn)行了更新。
3. Unix內(nèi)核概述
3.1進(jìn)程/內(nèi)核模式
正如之前描述的,CPU既可以運行在用戶態(tài),也可以運行在內(nèi)核態(tài)。當(dāng)應(yīng)用程序在用戶態(tài)下執(zhí)行時,不能直接訪問內(nèi)核的數(shù)據(jù)機構(gòu)與程序;當(dāng)應(yīng)用程序運行在內(nèi)核態(tài)下是,便沒有這些限制。
CPU模型為從用戶態(tài)轉(zhuǎn)換到內(nèi)核態(tài)提供了特殊的指令,反之亦然
進(jìn)程是動態(tài)的實體,通常只有有限的生命周期。
內(nèi)核本身并不是進(jìn)程,而是進(jìn)程的管理者。對于進(jìn)程/內(nèi)核模式假設(shè):請求內(nèi)核服務(wù)的進(jìn)程使用系統(tǒng)調(diào)用(System Call)的特殊編程機制。每個系統(tǒng)調(diào)用都設(shè)置了一組識別進(jìn)程請求的參數(shù),然后執(zhí)行與硬件相關(guān)的 CPU指令完成從用戶態(tài)到內(nèi)核態(tài)的轉(zhuǎn)換。
除了用戶進(jìn)程外,Unix系統(tǒng)還包括了幾個內(nèi)核線程的特權(quán)進(jìn)程,特點如下:
·以內(nèi)核態(tài)運行在內(nèi)核地址空間
·不與用戶直接交互
·系統(tǒng)啟動時創(chuàng)建,一直處于活躍狀態(tài)直到系統(tǒng)關(guān)閉
有幾種方式可以使進(jìn)程進(jìn)行用戶態(tài)與內(nèi)核態(tài)的轉(zhuǎn)換:
.進(jìn)程進(jìn)行系統(tǒng)調(diào)用
.正在執(zhí)行進(jìn)程的 CPU發(fā)出一個異常(Exception)信號(如無效的指令),由內(nèi)核代表產(chǎn)生異常的進(jìn)程處理異常
.外圍設(shè)備向 CPU發(fā)出一個中斷信號(Interrupt)以通知時間的發(fā)生(如 IO操作已完成);中斷信號交由內(nèi)核中的中斷處理程序來處理
.內(nèi)核線程被執(zhí)行:內(nèi)核線程運行在內(nèi)核態(tài)
3.2進(jìn)程實現(xiàn)
每個進(jìn)程都由一個進(jìn)程描述符(Process Descriptor)表示,該描述符包含了進(jìn)程當(dāng)前狀態(tài)的信息。
當(dāng)進(jìn)程暫停時,就把相關(guān)寄存器中的內(nèi)容保存在進(jìn)程描述符中,寄存器包括:
·程序計數(shù)器 &棧指針寄存器
·通用寄存器
·浮點寄存器
·包含 CPU狀態(tài)信息的處理器控制寄存器
·用來跟蹤進(jìn)程對 RAM訪問的內(nèi)存管理寄存器
當(dāng)進(jìn)程被重新恢復(fù)執(zhí)行時,內(nèi)核將進(jìn)程描述符中對應(yīng)的字段裝載到 CPU寄存器中。
當(dāng)進(jìn)程等待某一個事件時,會被置入進(jìn)程描述符等待隊列中等待事件的發(fā)生。
3.3可重入內(nèi)核
Unix內(nèi)核是可重入(Reentrant)的,是指多個進(jìn)程可以同時在內(nèi)核態(tài)下執(zhí)行。
在單處理器系統(tǒng)上只有一個進(jìn)程在運行,但是可以有多個進(jìn)程在內(nèi)核態(tài)下被阻塞,比如等待 CPU或者 IO操作完成
如果發(fā)生硬件中斷,可重入內(nèi)核就可以掛起正在執(zhí)行的進(jìn)程去響應(yīng)中斷,即使該進(jìn)程正處于內(nèi)核態(tài)。這種實現(xiàn)方式能夠提高發(fā)出中斷的設(shè)備控制器的吞吐量,否則該設(shè)備需要一直等待 CPU直到 CPU重新從內(nèi)核態(tài)切換為用戶態(tài)。
內(nèi)核控制路徑(Kernel Control Path)是指內(nèi)核處理系統(tǒng)調(diào)用,異?;蛘咧袛嗨鶊?zhí)行的指令序列。而可重入性內(nèi)核可以使得 CPU交錯執(zhí)行內(nèi)核控制路徑。
上圖顯示了交錯與非交錯的內(nèi)核控制路徑;其中
·User:在用戶態(tài)下運行一個進(jìn)程
·Excp:運行一個異常處理程序或者系統(tǒng)調(diào)用程序
·Intr:運行一個中斷處理程序
3.4進(jìn)程地址空間
進(jìn)程運行在私有地址空間中。處于用戶態(tài)的進(jìn)程涉及到私有棧,數(shù)據(jù)區(qū),代碼區(qū);處于內(nèi)核態(tài)的進(jìn)程訪問內(nèi)核的數(shù)據(jù)區(qū),代碼區(qū),但是使用另外的私有棧。
每個內(nèi)核控制路徑都引用自己的私有內(nèi)核棧
進(jìn)程間也能共享部分地址空間,實現(xiàn)進(jìn)程間通信。另外,Linux支持存在在磁盤上的文件部分映射到進(jìn)程的部分地址空間中。
3.5同步與臨界區(qū)
為了實現(xiàn)可重入內(nèi)核,需要引入同步機制,以防止不同的內(nèi)核控制路徑對同一個數(shù)據(jù)結(jié)構(gòu)的訪問出現(xiàn)不一致的狀態(tài)。
對全局變量的安全訪問一般是通過原子操作(Atomic Operation)實現(xiàn)。臨界區(qū)(Critical Region)是指存在這樣一段代碼,進(jìn)入這段代碼的進(jìn)程必須完成,之后另一個進(jìn)程才能進(jìn)入。
常見的幾種同步內(nèi)核控制路徑的方式:
3.5.1非搶占式內(nèi)核
當(dāng)進(jìn)程在內(nèi)核態(tài)執(zhí)行時,不能被任意掛起,也不能被其他進(jìn)程搶占。這樣,在單處理器系統(tǒng)中,中斷或者異常處理程序便不能修改內(nèi)核數(shù)據(jù)結(jié)構(gòu),保證了數(shù)據(jù)的一致性。
局限:
.對于多處理器系統(tǒng),非搶占式方式仍然不能避免不同 CPU上的內(nèi)核控制路徑并發(fā)訪問同一個數(shù)據(jù)結(jié)構(gòu)
.非搶占式內(nèi)核會降低系統(tǒng)的執(zhí)行效率
3.5.2禁止中斷
單處理器系統(tǒng)中還有一種同步機制:在進(jìn)入臨界區(qū)前禁止所有硬件中斷,離開后再重新啟用中斷。
局限:
.如果臨界區(qū)執(zhí)行耗時比較大,那么在較長時間內(nèi)會使得硬件處于凍結(jié)狀態(tài)
.禁止中斷只會對本地 CPU起作用,在多處理器系統(tǒng)中,還需要結(jié)合其他同步方式
3.5.3信號量
信號量(Semaphore)是一個廣泛使用的同步機制;其僅僅是一個與數(shù)據(jù)結(jié)構(gòu)(臨界區(qū))相關(guān)的計數(shù)器,所有內(nèi)核線程在訪問這個數(shù)據(jù)結(jié)構(gòu)之前都需要檢查信號量。信號量可以看作一個對象,組成如下:
·一個整數(shù)變量
·一個等待進(jìn)程的鏈表
·兩個原子方法:down() & up()
do態(tài):受影響的進(jìn)程或者內(nèi)核控制路徑完全處于凍結(jié)的狀態(tài)。
為了減少內(nèi)核控制路徑交錯執(zhí)行時出現(xiàn)死鎖的概率,有些操作系統(tǒng)通過按規(guī)定的順序請求信號量來避免死鎖。
3.6信號與進(jìn)程間通信
Unix信號(Signal)是一種把系統(tǒng)事件上報給進(jìn)程的機制。系統(tǒng)事件分為兩種
.異步通告:如終端輸入 ctrl-c,內(nèi)核會向前臺進(jìn)程發(fā)出中斷信號
.同步錯誤或者異常:如進(jìn)程訪問內(nèi)存非法地址時,內(nèi)核會向進(jìn)程發(fā)送異常信號
進(jìn)程對收到的信號的處理方式有:
.忽略該信號
.異步地執(zhí)行一個指定的過程(信號處理程序)
同時,如果進(jìn)程不指定處理方式,內(nèi)核就會根據(jù)信號類型的不同,有五種默認(rèn)的執(zhí)行操作:
·終止進(jìn)程
·將進(jìn)程上下文與地址空間 core dump,并終止進(jìn)程
·忽略信號
·掛起進(jìn)程
·恢復(fù)進(jìn)程
Unix在用戶態(tài)下的進(jìn)程間通信機制有:信號量,消息隊列,共享內(nèi)存等。
該信號量與內(nèi)核中的信號量類似,之不過是在用戶態(tài)下;消息隊列可以通過指定的隊列允許進(jìn)程之間交換消息;共享內(nèi)存為進(jìn)程之間交換和共享數(shù)據(jù)提供了最快的方式。
3.7進(jìn)程管理
系統(tǒng)調(diào)用fork():創(chuàng)建新的進(jìn)程;_exit():終止進(jìn)程;exec():裝入一個新的程序。
3.8內(nèi)存管理
3.8.1虛擬內(nèi)存
虛擬內(nèi)存(Virtual Memory)是一種抽象,作為一種邏輯層處于應(yīng)用程序內(nèi)存請求與硬件內(nèi)存管理單元(Memory Management Unit)之間;虛擬內(nèi)存的優(yōu)勢有:
·多個進(jìn)程可以并發(fā)執(zhí)行
·應(yīng)用程序所需的內(nèi)存大于實際可用物理內(nèi)存時也可以運行
·程序只有部分代碼裝入內(nèi)存時進(jìn)程也可以執(zhí)行
·允許進(jìn)程訪問可用物理內(nèi)存的子集
·程序可重定位(可以把程序放在物理內(nèi)存的任何地方)