你知道操作系統(tǒng)何時(shí)運(yùn)行?
請各位思考以下問題:在你閱讀本文的這段時(shí)間內(nèi),計(jì)算機(jī)中的操作系統(tǒng)在運(yùn)行嗎?又或者僅僅是 Web 瀏覽器在運(yùn)行?又或者它們也許均處于空閑狀態(tài),等待著你的指示?
這些問題并不復(fù)雜,但它們深入涉及到系統(tǒng)軟件工作的本質(zhì)。為了準(zhǔn)確回答這些問題,我們需要透徹理解操作系統(tǒng)的行為模型,包括性能、安全和除錯(cuò)等方面。在該系列文章中,我們將以 Linux 為主舉例來幫助你建立操作系統(tǒng)的行為模型,OS X 和 Windows 在必要的時(shí)候也會(huì)有所涉及。對那些深度探索者,我會(huì)在適當(dāng)?shù)臅r(shí)候給出 Linux 內(nèi)核源碼的鏈接。
這里有一個(gè)基本認(rèn)知,就是,在任意給定時(shí)刻,某個(gè) CPU 上僅有一個(gè)任務(wù)處于活動(dòng)狀態(tài)。大多數(shù)情形下這個(gè)任務(wù)是某個(gè)用戶程序,例如你的 Web 瀏覽器或音樂播放器,但它也可能是一個(gè)操作系統(tǒng)線程??梢源_信的是,它是一個(gè)任務(wù),不是兩個(gè)或更多,也不是零個(gè),對,永遠(yuǎn)是一個(gè)。
這聽上去可能會(huì)有些問題。比如,你的音樂播放器是否會(huì)獨(dú)占 CPU 而阻止其它任務(wù)運(yùn)行?從而使你不能打開任務(wù)管理工具去殺死音樂播放器,甚至讓鼠標(biāo)點(diǎn)擊也失效,因?yàn)椴僮飨到y(tǒng)沒有機(jī)會(huì)去處理這些事件。你可能會(huì)憤而喊出,“它究竟在搞什么鬼?”,并引發(fā)騷亂。
此時(shí)便輪到中斷大顯身手了。中斷就好比,一聲巨響或一次拍肩后,神經(jīng)系統(tǒng)通知大腦去感知外部刺激一般。計(jì)算機(jī)主板上的芯片組同樣會(huì)中斷 CPU 運(yùn)行以傳遞新的外部事件,例如鍵盤上的某個(gè)鍵被按下、網(wǎng)絡(luò)數(shù)據(jù)包的到達(dá)、一次硬盤讀取的完成,等等。硬件外設(shè)、主板上的中斷控制器和 CPU 本身,它們共同協(xié)作實(shí)現(xiàn)了中斷機(jī)制。
中斷對于記錄我們最珍視的資源——時(shí)間——也至關(guān)重要。計(jì)算機(jī)啟動(dòng)過程中,操作系統(tǒng)內(nèi)核會(huì)設(shè)置一個(gè)硬件計(jì)時(shí)器以讓其產(chǎn)生周期性計(jì)時(shí)中斷,例如每隔 10 毫秒觸發(fā)一次。每當(dāng)計(jì)時(shí)中斷到來,內(nèi)核便會(huì)收到通知以更新系統(tǒng)統(tǒng)計(jì)信息和盤點(diǎn)如下事項(xiàng):當(dāng)前用戶程序是否已運(yùn)行了足夠長時(shí)間?是否有某個(gè) TCP 定時(shí)器超時(shí)了?中斷給予了內(nèi)核一個(gè)處理這些問題并采取合適措施的機(jī)會(huì)。這就好像你給自己設(shè)置了整天的周期鬧鈴并把它們用作檢查點(diǎn):我是否應(yīng)該去做我正在進(jìn)行的工作?是否存在更緊急的事項(xiàng)?直到你發(fā)現(xiàn) 10 年時(shí)間已逝去……
這些內(nèi)核對 CPU 周期性的劫持被稱為滴答,也就是說,是中斷讓你的操作系統(tǒng)滴答了一下。不止如此,中斷也被用作處理一些軟件事件,如整數(shù)溢出和頁錯(cuò)誤,其中未涉及外部硬件。中斷是進(jìn)入操作系統(tǒng)內(nèi)核最頻繁也是最重要的入口。對于學(xué)習(xí)電子工程的人而言,這些并無古怪,它們是操作系統(tǒng)賴以運(yùn)行的機(jī)制。
說到這里,讓我們再來看一些實(shí)際情形。下圖示意了 Intel Core i5 系統(tǒng)中的一個(gè)網(wǎng)卡中斷。圖片中的部分元素設(shè)置了超鏈,你可以點(diǎn)擊它們以獲取更為詳細(xì)的信息,例如每個(gè)設(shè)備均被鏈接到了對應(yīng)的 Linux 驅(qū)動(dòng)源碼。
鏈接如下:
讓我們來仔細(xì)研究下。首先,由于系統(tǒng)中存在眾多中斷源,如果硬件只是通知 CPU “嘿,這里發(fā)生了一些事情”然后什么也不做,則不太行得通。這會(huì)帶來難以忍受的冗長等待。因此,計(jì)算機(jī)上電時(shí),每個(gè)設(shè)備都被授予了一根中斷線,或者稱為 IRQ。這些 IRQ 然后被系統(tǒng)中的中斷控制器映射成值介于 0 到 255 之間的中斷向量。等到中斷到達(dá) CPU,它便具備了一個(gè)完好定義的數(shù)值,異于硬件的某些其它詭異行為。
相應(yīng)地,CPU 中還存有一個(gè)由內(nèi)核維護(hù)的指針,指向一個(gè)包含 255 個(gè)函數(shù)指針的數(shù)組,其中每個(gè)函數(shù)被用來處理某個(gè)特定的中斷向量。后文中,我們將繼續(xù)深入探討這個(gè)數(shù)組,它也被稱作中斷描述符表(IDT)。
每當(dāng)中斷到來,CPU 會(huì)用中斷向量的值去索引中斷描述符表,并執(zhí)行相應(yīng)處理函數(shù)。這相當(dāng)于,在當(dāng)前正在執(zhí)行任務(wù)的上下文中,發(fā)生了一個(gè)特殊函數(shù)調(diào)用,從而允許操作系統(tǒng)以較小開銷快速對外部事件作出反應(yīng)??紤]下述場景,Web 服務(wù)器在發(fā)送數(shù)據(jù)時(shí),CPU 卻間接調(diào)用了操作系統(tǒng)函數(shù),這聽上去要么很炫酷要么令人驚恐。下圖展示了 Vim 編輯器運(yùn)行過程中一個(gè)中斷到來的情形。
此處請留意,中斷的到來是如何觸發(fā) CPU 到 Ring 0 內(nèi)核模式的切換而未有改變當(dāng)前活躍的任務(wù)。這看上去就像,Vim 編輯器直接面向操作系統(tǒng)內(nèi)核產(chǎn)生了一次神奇的函數(shù)調(diào)用,但 Vim 還在那里,它的地址空間原封未動(dòng),等待著執(zhí)行流返回。
這很令人振奮,不是么?不過讓我們暫且告一段落吧,我需要合理控制篇幅。我知道還沒有回答完這個(gè)開放式問題,甚至還實(shí)質(zhì)上翻開了新的問題,但你至少知道了在你讀這個(gè)句子的同時(shí)滴答正在發(fā)生。我們將在充實(shí)了對操作系統(tǒng)動(dòng)態(tài)行為模型的理解之后再回來尋求問題的答案,對 Web 瀏覽器情形的理解也會(huì)變得清晰。如果你仍有問題,尤其是在這篇文章公諸于眾后,請盡管提出。我將會(huì)在文章或后續(xù)評論中回答它們。下篇文章將于明天在 RSS 和 Twitter 上發(fā)布。