統的概念
雖然定義總是生硬、乏味、令人費解,但是它畢竟是概括性zui強、zui能體現水平的,所以我們還是要在開始就給出操作系統定義: 操作系統是應用程序的運行環境。 夠精辟吧! 可能運行環境這個術語令你如墜云端,它太廣泛、太抽象了。你一定在問運行環境到底是什么?簡單地講,運行環境是一種即服務和控制于一體地容器。 如果你沒有理解環境這個概念,我可以舉個并不貼切的社會實例。 在開發區中可以看到許多企業孵化池或產業園,其中入住了各種各樣的企業,孵化池或產業園的管理機構會統一為其中的企業辦理各種工商、保險、衛生醫療等手續、提供后勤、治安等基礎服務,企業需要某些政務服務時,可以通過管理機構去和政府,處理相關事宜,而不需要親自去處理這些和企業業務無關的政務活動,因此可以抽出身來集中精力在業務上。孵化池和產業園為企業提供了統一、普遍地服務和管理,是企業運作的外在環境。操作系統從這個意義上來說,類似于產業園的管理結構,為應用程序——好比企業——提供基礎服務和管理。 當然,我們現在并不指望你立刻認識到操作系統深刻內涵,對它的認識需要在不斷地使用和思考中消化和積累,在本期雜志中,我們將從各種角度介紹“運行環境”這個術語的真實含義,并在今后各期雜志中分階段、分層次的展開學習操作系統的各個領域。相信在不久的將來,你就能和我們一起認清它的廬山真面目了。操作系統產生背景 想要認清一個人,是從小認識他。對技術的理解也是如此,我們必須了解它的產生原因和發展過程,才能較為全面的認識該技術所解決的問題,認識它在學科發展中所處的地位。對比技術發展各個階段的特點,才能認清該技術的優劣。同樣,我們想要把握操作系統的特性,還是先把操作系統放在時間軸上看看它的來龍去脈吧! 操作系統并不是計算機出現之初就有的,zui初的計算機科學中并不存在操作系統這個概念,所有任務都直接運行于硬件之上。那時的任務大多集中于科學計算領域,系統硬件實現相對簡單、直接,任務對i/o操作的要求也比較低,將結果記錄到磁帶機之類的簡單設備中足矣。老程序員們大多采用手工或是用打孔機的方式將將二進制數據和程序輸入機器內存,然后執行計算,zui后,將結果保存到磁帶機上。一旦出現錯誤,機器上的調試燈會將保存在寄存器中的錯誤代碼反映出來,程序員們會據此去分析錯誤所在。
隨著科學計算任務變得越來越復雜,計算機逐漸被應用到了科學計算以外的其它領域。硬件設備比以前更加豐富和復雜了,i/o操作要求大幅提高,程序規模迅速擴大,需要調試的錯誤更是直線上升,直接操作硬件,對程序員來說變得越發困難。
于是出現了語言、編譯系統,幫助程序員簡化開發工作;出現了操作系統,幫助程序員管理和操作硬件設備。程序員們可以將精力集中于開發需要的任務,煩瑣的如任務裝載、分配/釋放內存、內存尋址、設備驅動、數據存儲等等硬件相關操作統統交給操作系統管理——真可以說是生產力的一次解放。
時代繼續發展,多用戶多任務時代的來臨,使得系統管理更加強調資源共享性。用戶直接操作系統資源顯然有悖于上述精神,因此資源合理分配與保護更為操作系統發展提供了新的挑戰和機遇,同時奠定了操作系統*的地位,從此,操作系統成為為軟件體系中zui基礎,zui重要的組成部分了。操作系統的任務從操作系統的起源可以看出,操作系統的核心任務是作為硬件和應用程序之間的一個中間層,或者說是應用程序的一個操作平臺,通過它應用程序和系統硬件隔離開,應用程序利用它提供的服務完成硬件相關操作。
總而言之,操作系統方便了應用程序運行,保護了系統資源。具體地講,操作系統為用戶帶來了幾個方面的好處:易操作性: 操作系統是用戶和計算機之間的接口,它大大簡化了用戶執行任務的復雜程度。
作為應用程序的執行環境:它為程序員建立應用程序提供了必要的編輯環境、編譯環境和調試工具;為程序的執行提供了載入服務和資源分配服務;為數據存取提供了i/o訪問服務;為數據格式轉化和定位提供了文件操作服務;為程序的安全運行提供了權限控制服務;為程序運行失敗提供了錯誤報告服務等等系統服務,從此,程序員和用戶都不再需要關心那些令人生畏的計算機體系結構細節,可以全心全意地開發應用程序了。
有效性:從另一個角度看待操作系統,可以將它認為是一個計算機資源管理系統。 由于系統中資源種類各異,用法也大不相同,如果直接由用戶管理這些資源,比如內存分配,時鐘計時,i/o驅動,存儲維護,勢必要求用戶具有豐富的軟硬件知識,深刻把握計算機系統結構,否則資源將難以合理使用,zui終造成系統混亂,甚至崩潰。而且現代的多用戶操作系統更是要求系統資源共享,資源必須合理分配給多用戶、多任務,只有采用一定的調度策略和分配策略,才能保證資源被公平有效的利用。所以,配置資源成了提高性能的關鍵——如同資源配置是提高生產力的關鍵一樣。
安全性:安全性是操作系統為我們提供的另一個重要的特點,它為我們提供了多層面的安全保障。
首先,操作系統作為系統硬件和用戶的中間平臺,禁止應用程序直接操作硬件,禁止應用程序直接訪問內存,執行特權指令。多數系統都將應用程序運行限制在用戶空間(低特權級),而操作系統則運行于內核空間(高特權級),應用程序只有通過系統調用請求操作系統所提供的接口,才能通過操作系統間接執行和硬件相關的操作或是執行特權指令。因此保護了系統不被惡意的應用程序破壞或非法操作。
其次,多任務多用戶操作系統必須保證,不同任務之間信息不能泄漏,因此需要為任務劃分各自的私有空間和對其進行訪問控制。對不同用戶進行相應的*和認證,可以保護用戶各行其是,互不侵犯。
總之,操作系統安全涉及方方面面,健壯的操作系統必須能多方位地保證任務安全執行。 易擴展:計算機技術的高速發展和計算機日益普及,計算機硬件設備不斷推陳出新,這要求操作系統提供的服務也能夠日新月異,因此要求操作系統具有良好的擴展性。
由于操作系統對系統資源和服務進行了抽象,屏蔽了底層細節,統一了上層接口,添加設備或服務成了一件輕而易舉的事,需要做的僅僅是,在設備或服務規定的接口下完成新的實現即刻。 什么是資源?
資源概念在操作系統中使用得相當廣泛,內存、磁盤、文件、處理器、時鐘等等軟硬件都可以劃歸到資源范疇。資源的概念其實很好理解,概括來講,系統中的資源指的是系統提供給進程使用的特殊實體,進程通過向操作系統請求獲得這些實體,另外,系統分配這些實體給進程前,進程需要掛起等待。凡是滿足上述條件的實體就屬于資源。操作系統的演化和其它任何事務一樣,操作系統并非一成不變。迄今為止,它已經經歷了半個多世紀的發展,已經形成了一個龐大的家族。從個人計算機到工作站,從通用系統到系統,從嵌入式到虛擬機,可謂形式豐富多樣。我們難以將所有操作系統囊括,只希望提綱挈領地介紹在操作系統發展進程中具有代表性的幾種系統,理清它的演化脈絡。
進化歷程 : zui早的操作系統是簡單的單道批處理系統。它的功能相當簡陋,只能串行執行預先組織好的任務組。早先的系統一次只能運行一個任務,每個任務必須先裝入,再等執行完后才能裝入下一個任務,重復的裝入浪費了大量的時間。單道批處理系統的出現,大大的提高了系統吞吐率。 事情并非總如想象般順利。
由于數據存儲時所消耗的時間——i/o操作時間——相比數據處理時間——cpu操作時間——要高出數倍(往往在20倍以上),所以程序運行到i/o操作期間,cpu總是需要停下來(掛起)等待數據傳輸完成,無形中浪費了大量寶貴的時間,任務組中后續程序的執行也因此被延遲了。如何避免數據傳輸等待帶來的時間浪費呢?能否在進行傳輸期間,解放cpu去執行別的任務呢? 為解決這個瓶頸,單道批處理系統進化到了多道批處理系統。
所謂多道就實際就是說,處理器(當然現在談到的都屬于單處理器系統)可以交錯運行多個程序,某個任務掛起時,運行另一個程序。這樣一來, cpu等待數據傳輸造成的時間浪費問題得以解決,系統吞吐率又一次得到了提高。 計算機的發展使得任務不再僅僅局限于科學計算,越來越多的應用于辦公、生活等日常活動中。科學計算中的任務多數執行路徑都是固定不變,預先定義好的,只需要給定輸入,得到結果期間程序執行中途不需要外界干預,與之不同,辦公,生活中的許多任務都必須和用戶不斷交互,任務結果隨時都會因為用戶的選擇改變。這時的系統變得更公開、更普遍,往往允許多個用戶可以同時使用。交互模式和共用模式需要任務響應時間盡可能的快(超過20秒的話,人的思維就容易被打斷或變得很不耐煩),這樣才能讓多個用戶都滿意,于是操作系統開始采用分時技術,處理器的運行時間分成數片,均分或依照一定權重派發給系統中的用戶使用。這種將處理器虛擬給多用戶共同使用的方法,不但可以滿足快速響應,而且也可以使得所有用戶獲得計算機*是在為自己服務的假象。
上面給出了操作系統發展的主流路線:單道批處理——多道批處理——分時系統,除此以外現在還出現了許多分布式操作系統,嵌入系統,不過總體技術思路都仍然脫離不了多道、分時等概念。操作系統內容 操作系統的演化使得其功能變得愈來愈強大,但結構也越來越復雜。在以方便用戶(包括開發人員和終端用戶)為宗旨的思想下,操作系統不斷集成新功能,新服務。回憶從前大家使用的dos系統僅僅只需要一張軟盤,而如今的windows系統或linux系統動輒就需要數張光盤,可見已經從過去的麻雀變成了恐龍——雖然它們都有五臟六腑。
雖然變成了恐龍,但是其結構還時相對穩定,清晰的。和軟件工程提出的思想一致,操作系統也采取了分層結構,越向上層抽象都越高,越接近用戶;相反越向下層,越靠近硬件,抽象也相對接近硬件。而且高層軟件依靠下層軟件提供的服務,再加上本身提供附加服務為更高層服務。總體來講呈現倒金子塔形式。
下面我們就簡要分析一下操作系統的體系結構,然后再談談操作系統設計時需要主要考慮的問題。操作系統組成 在形形色色的操作系統之中,組成結構不盡相同。因為同樣目的實現的手段可以自由選擇,所以其組成也有很大差異,我們選取zui普遍的操作系統(unix)組成結構,向大家揭示操作系統的體系結構的大致框架。對于各種操作系統之間的具體差異,大家可以以下面講述的結構對比認識。(注意我們這里所說的操作系統屬于宏觀概念,接近于操作系統發行版,不但包括了內核,還包含了學多系統軟件和基礎應用軟件。)
我們用一組簡單的數學公式來描述操作系統的組成要素: 操作系統 = 內核+系統程序 系統程序 = 編譯環境 + api + aui 編譯環境 = 編譯程序+連接程序 + 裝載程序 api = 系統調用 + 語言庫函數(c,c++,java,etc) aui = shell + 系統服務例程(如x服務器等)+應用程序(瀏覽器,字處理,編輯器) 操作系統zui底層的組件是內核,其上層搭建了許多系統軟件。系統程序包括三個部分。這三個部分分別是:編譯環境、應用程序接口和用戶接口。編譯環境包含匯編,c 等低語言編譯程序,連接程序和裝載程序,這些程序負責將文本格式的程序語言轉變為機器能識別和裝載的機器代碼;應用程序接口(api)包含內核提供的系統調用接口和語言庫,系統調用是為了能讓應用程序使用內核服務,語言庫函數則是為了方便應用程序開發,所以將一些常用的基礎功能預先編譯以供使用,比如對c語言來說常用的c庫有gun c等;用戶接口(aui)包括我們熟悉的shell(關于shell 應該專門寫一個教程)、系統服務程序和常用的應用程序。
這些部分并非所有的操作系統都必須一個不少的包含,不過其中大多數功能都應該提供,尤其內核,系統調用,shell這些基本組件,它們都屬于操作系統*組件,其它組件是否包含需要根據具體系統的要求和應用環境決定,你也可以將其歸為操作系統之外的附加部分。
系統程序:系統程序是相對應用程序而言的,應用程序針對終端用戶需求完成功能,而系統程序則是為了簡化應用程序的開發而存在的,比如數據庫系統為了應用程序提供了有效的數據傳輸,存儲服務;還有編程語言的執行環境——它由c庫實現——也屬于一種系統程序,它為應用程序開發提供了諸如i/o操作例程,圖形庫,計算庫等等基礎服務。可見系統程序范圍覆蓋很廣,只要面相服務群體不是zui終用戶的軟件都可以劃歸到系統軟件中來。
內核概念 操作系統zui核心,zui基礎的組件就要屬內核了——內核和操作系統的其它系統軟件或應用程序本質的區別在于內核運行在高特權級,和硬件直接交互,操作權限幾乎不收任何限制,因此內核程序編寫也要求格外謹慎,必須保證效率和可靠。
特權級別:現代體系結構中往往為了保護操作系統(內核)的數據不被應用程序訪問,以免關鍵數據泄露或系統被破壞,將系統(硬件機制)劃分為不同的特權級別,敏感數據存在高特權級,且還規定了一些特權指令,其它級別的任務不能訪問敏感數據和使用這些特權指令,只有處于特權級別的任務才有權使用。比如ox86體系結構中存在4個特權級別(0,1,2,3)linux操作系統將內核存在0級,其它任務運行在3級。0級被稱為內核空間,3級被稱為用戶空間。內核設計的主要任務內核作為操作系統的核心,運行級別zui高。其它系統程序都必須通過它才可以使用系統資源,獲取系統服務。所以內核使用zui為頻繁,一切系統行為無論巨細都要通過內核參與。因此內核運行效率和正確性對整個系統的運行效率和可靠性至觀重要,如果內核效率稍微下降,那么在應用程序中就必然造成層層放大。
內核要求率,所以它必須自系統運行起就要載入內存,并且在運行期間一直駐留在內存中,直到系統關閉。這是內核與其它應用程序或系統程序的另一個顯著區別。雖然說內存今天已經不再是天價了,但是畢竟內存容量有限,所以內核大小不能過大(linux內核只有幾m或十幾m,甚至可以裁減得更小),因此內核只應該包含zui基礎和核心的功能,其它附加功能應該盡量提到用戶空間完成。
那么到底有那些功能是操作系統使用zui頻繁,zui需要在內核中實現的呢?內核直接架構于硬件資源之上,因此首先要做的就是對硬件的資源管理。因此內核必須負責:內存管理,進程和進程調度(對cpu的管理),文件系統管理,i/o處理等任務。
我們的雜志核心就是在解釋內核原理的基礎上,帶領大家學習內核級別的開發,也就是說進行核心開發。本期僅僅給大家一個概念上的說明,描述內核設計需要完成的主要任務,至于具體內核各部分的詳細討論在后續期刊中將逐步展開。
內核至少需要包含如下幾個模塊。 進程管理:進程是操作系統中的執行代碼,是任務在系統內的動態化身。內核必須負責將任務抽象為進程,而且必須能將進程執行,能為進程分配資源,維護進程的執行狀態,提供進程間通訊方法。更進一步講,進程管理還必須保證進程運行的可靠性,因此需要提供進程同步,互斥,防死鎖等等服務,另外進程調度也是進程管理中的重要任務。 內存管理:計算機存儲部件由快到慢、由小到大分為緩存、內存和磁盤。其中zui主要和必須是內存,內存管理包括內存的分配和釋放,以及訪問保護等。另外對使用虛擬內存的系統,內存管理還包含虛擬內存管理,磁盤交換管理,內存影射等等。
文件系統:文件是多數系統中用戶使用和管理數據的主要方式,文件系統需要負責用戶文件訪問,訪問權限控制,文件格式轉換,數據傳輸等一系列問題。 設備管理:除了存儲設備外,系統還有大量外設需要操作系統管理,比如時鐘,網卡,鍵盤,磁盤等等,設備管理需要負責驅動這些設備為上層調用服務。
i/o管理:操作系統中i/o管理負責處理復雜的i/o操作,其中包括i/o緩沖和磁盤調度等。 另外中斷管理也是操作系統內核應該實現的功能。
以上是操作系統內核設計要考慮的主要問題,其中各種模塊彼此相互交錯、相互利用。不過這些模塊的劃分并不是的,在實際系統中可能有不同的組合或更細致地劃分,因此我們不必追究模塊的具體內容,需要關注的是內核究竟需要完成那些功能。 內核模塊大致也有層次之分,我們可以這樣理解層次含義:直接和硬件作用的是硬件抽象層,和用戶更靠近的屬于邏輯抽象層。 所謂硬件抽象層,是指管理硬件設備的模塊,比如存儲管理、設備管理這些模塊將硬件功能抽象為內核數據結構和接口函數,以供上層使用。比如磁盤設備驅動,需要將磁盤設備功能抽象為打開open,寫入(write),讀取(read)等接口函數;內存管理需要將內存抽象為頁、段等結構體。然后分配、合并、釋放等工作都是通過操作這些抽象得來的結構體,再由這些結構影射到內存的物理實體上去的完成實際操作的。
所謂邏輯抽象層zui主要的目的是為了貼近用戶需求,zui重要的邏輯抽象模塊就是文件系統,文件系統的存在*是從用戶角度出發設計的,因為用戶zui能接受以用文件形式包裝的信息,所以文件系統屬于邏輯上的抽象,因為物理設備中沒有對應文件的實體。
對于進程管理來說,其中進程執行和調度要和處理器打交道,應該說屬于硬件抽象層,但其中進程狀態維護,進程通訊等更接近用戶使用,因此可以歸結到邏輯抽象層。 另外i/o管理和中斷管理些模塊,在內核中屬于為其它模塊服務的借用力量,它們主要被文件系統或設備管理模塊使用,但總之是面向硬件的,所以也可以將其歸為硬件邏輯層。 linux操作系統 在眾多商業操作系統和免費操作系統中,linux占有獨到地位,它不但功能強大,接近于工業強度,而且結構設計幽雅,具有良好的擴展性和移植性,接口定義規范,基本和unix系統兼容。更為重要的優勢在于linux操作系統是的開源軟件,它的產生揭開了開元運動的新紀元,對自由軟件發展起到了前所為有的推動作用。 linux開放性,也就是它不拘一格的拿來主義精神,吸引了無數軟件愛好者熱情的投入到其開發中去,因此linux是當今發展zui快,范圍zui廣的開元軟件之一。它是社區中大家zui樂意討論和參與的項目,也正是這種開源精神使linux成為操作系統愛好者的良師益友,它在教育意義上的貢獻是的。從這節起我們將進入linux世界去探索操作系統軟件的嚴謹,去感受linux的可愛。linux操作系統的起源 linux的*個版本誕生于1991年,它的作者就是現在大名鼎鼎linus torvalds,這個芬蘭小伙子據說zui初是在做一個作業調度系統的學校家庭作業,后來他突發靈感開始著手將系統改造為一個實用的操作系統,他在開發初期借助了當時zui負盛名的教育類操作系統minx的一些思想和成果,但他的雄心是要將自己這個系統變的比minx更實用、更強健,因此他決定把自己的系統代碼公布于眾,并且歡迎任何支援者來修改和擴充linux系統——這正是我們現在耳聞祥熟的gun協議的權益——linux選擇了當時在世界上zui受推崇的un ix系統接口標準:posix.1來作為自己的內核系統調用接口,從此linux成為了unix風格操作系統家族中的新貴,而且是一個代碼*公開的操作系統。 linux的生命力來自于它的開源思想,自linus公開linux代碼一來,世界各地的軟件工程師和愛好這不斷積極地對linux系統今進行修改和加強,先后將其版本從0.1 提高到2.0 、2.2、2.4到如今的2.6,同時linux也被從初期的x86平臺移植到了powerpc、sparc、mips、68k等幾乎市面上能找到的所有體系結構上。更另人激動的是,拜開源運動之新風,數不勝數的應用軟件出現在linux系統之上,這樣大大加強了linux系統的實用能力。 linux作為開源軟件中的桂冠,越來越受到歡迎,毫無疑問地成為人氣zui旺,zui活躍的gun項目,圍繞linux的社區雨后春筍般的出現,這一切都預示著linux將在教育領域,在工業領域在政治領域將得的成功。linux 操作系統的技術特點 linux系統吸收了unix操作系統的精華思想——“簡單就是美”,因此它采用了緊縮內核結構,只在內核中實現那些必要的功能,盡量保持內核精悍短小。至于那些豐富多彩的附加功能統統交給用戶空間的庫函數或其它系統軟件或應用軟件完成。 有時大家將直接將linux內核和 linux操作系統化等號,這也沒錯的。而我們上文提到的操作操作系統多數情況不僅僅只內核而且還只內核之上的系統程序,可以說是廣義的操作系統概念,希望大家區別。 為了能受益于unix系統的影響力,linux采用了unix的系統調用接口標準poxis.1,保證了和unix系統的有限兼容,從而抓住了很大一部分unix技術人員。 另外linux起源于小型計、通用算機,并非針對大型和計算機設計,因此結構復雜性和規范性都比較適中。 還有就是目前多數linux操作系統版本都是以服務器為出發點,因此網絡功能和系管理能力突出,多數應用也是專為網絡管理服務的,對于個人用戶所關注的桌面應用和嵌入應用關注的實時性支持尚且有限(今年linux發展的一個重要議題就是針對桌面和嵌入開發相應的內核版本)。 linux 內核的特點 linux是一種是實用性很強的現代操作系統,開發它的中堅力量是軟件工程師,因此多以實用性和效率為出發點,很多地方還考慮了工業規范和兼容性等因素,因此不同于教學性操作系統追求理論上的性,linux系統內核zui注重的問題是實用和效率。 下面我們簡要歸納一下linux內核的特色。 *,linux內核被設計成單巨內核(monolithic?)結構(相對微內核而言,微內核是一種功能更貼近硬件的核心軟件,它一般僅僅包括初等內存管理、同步原語、程間通訊機制、i/o操作和中斷管理,這樣做有利于擴展性和移植性。但是微內核與諸如文件管理、設備驅動、虛擬內存管理、進程管理等其它上層模塊之間需要有較高的通訊開銷,所以目前多集中在理論教學領域,對工業應用效率難以保證。),因此效率高,緊湊性強。 第二, 2.6版本前linux內核是單線程結構——所謂但線程結構是說同一時間只有一個執行線程(內核中的執行程序)允許在內核中運行,不會被調度程序打斷運行其它任務,這種內核被成為非搶占的,它的好處在于內核中沒有并發任務(單處理器而言),因此避免了許多復雜的同步問題,但其不利影響是非搶占特性延遲了系統響應速度,新任務必須等待當前任務在內核執行退出才能獲得運行機會。工業控制領域需要高響應速度,因此2.6版本后由于robert love等人的貢獻,將搶占技術引入了linux內核,使得其變為內核搶占系統,當然付出的代價是同步操作進一步復雜化了。 第三,為了保證能方便地支持新設備、新功能,又不會無限擴大內核規模,linux系統對設備驅動或新文件系統等采用了模塊化方式,用戶在需要時可以現場動態加載,使用完畢可以動態卸載。同時對內核,用戶也可以定制,選擇適合自己的功能,將不需要的部分剔除出內核。這兩種技術都保證了內核的緊湊性和擴展性。 第四,linux內核純粹是一種被動調用服務對象,所謂被動是因為它為用戶服務的*方式是用戶通過系統調用來請求在內核空間運行某個函數。內核本身是一種函數和數據結構的集合,不存在運行的內核進程為用戶服務(雖然linux的確存在一種被稱為內核線程的進程,但它并不是用來服務于用戶的,僅僅作為系統自身的服務目的)。 第五, linux內核的采用虛擬內存技術使得內存空間虛擬擴展到了4gb之多,其中0-3g屬于用戶空間,稱為用戶段,3g-4g屬于用戶空間,稱為內核段。這樣使得用戶編寫程序可以使用遠遠大于實際內存的存儲空間。 第六, linux的文件系統zui大特點是實現了一種抽象文件模型——vfs(虛擬文件系統),該文件系統屬于unix風格。使用虛擬文件系統屏蔽了各種不同文件系統的內在差別,使得用戶可以使用同樣的方式訪問各種不同格式的文件系統,可以毫無區別地在不同介質不同格式的文件系統之間使用vfs提供的統一接口交換數據。這種抽象為linux帶來了無限活力。 第七, linux提供了一套很有效的延遲執行機制——下半部分,軟中斷,tasklet和2.6新引入的工作列隊等,這些技術保證了系統可以針對任務的輕重緩急,更細粒度的選擇執行時機。保證了系統運行時盡量在安全時間(不關中斷)。 linux除了以上提到的特色外,還有許多其它突出特點,我們將在以后各期的介紹中有序地介紹。如果對上述特色有疑問的話,請別著急,后面的學習將為你解答。 linux 操作系統內核結構 linux內核雖然實現和unix系統有很大不同,但是其結構還基本保持和unix雷同,其中功能也和我們前面提到的操作系統內核要求大體一致。 請見下圖 下面我們簡要說明一下個模塊之間的。 用戶空間的任何程序如果需要使用內核提供的服務,都必須經過系統調用,因此系統調用層和內核中大多數模塊都留有接口,它們或是用來控制系統服務屬性(如sys_fnctl設置文件操作屬性;sys_nice設置進程時間片),或是從內核提取數據(如sys_time獲得由時間中斷維護的系統計時),或請求內核分配資源(brk擴展進程堆內存)。 文件系統包含vfs和各種實際文件系統。vfs為實際文件系統抽象了統一接口,而實際文件系統提供自身具體實例操作方法。另外在linux中和unix一樣設備被巧妙的歸屬為特殊文件,受文件系統抽象和管理,因此其操作方式和文件系統一致。文件系統將對設備的操作遞交給實際的設備驅動處理。 linux中設備管理將設備被區分為塊設備——可以隨機訪問,如磁盤——和字符設備——只能順序訪問,如鍵盤。字符設備結構簡單,文件系統可將請求直接提交給字符設備驅動處理,但是對于塊設備,由于頻繁的隨機訪問需要反復進行磁盤尋址操作,這樣會對系統載核的帶來沉重負擔,因此內核對塊設備的請求必須加以整合,比如對請求排隊、合并、然后有選擇地派發給物理設備;另外讀取設備時還需要在內存中進行緩沖磁盤塊。因此在請求被提交給塊設備前必須經過i/o層處理進行預處理,在磁盤塊被讀取后必須由i/o層進行塊緩沖處理。 中斷管理系統負責為設備服務,它相比輪詢等方式節約了cpu周期,另外時鐘中斷還要負責更新系統時間,觸發進程調度。 內存是系統中的核心資源之一,是數據存儲和傳遞的必被條件,因此管理系統不但系統調用需要使用,而且幾乎系統中所有模塊都多多少少地需要使用內存管理系統的函數。文件系統、i/o系統用來緩沖數據都需要分配內存,進程管理中的進程數據存儲,地址影射都需要內存,堆的增長也需要動態請求內存;還有就是進程通訊中的一個有效方法就是利用共享內存來實現的。 進程管理除了和內存管理和進程通訊有關外,也和文件系統有重要關聯,因為進程資源中文件毫無疑問屬于zui重要的部分之一,因此進程管理系統也必須和文件系統交互。 其中個個模塊不是孤立的,而是萬千,對于其中奧秘,希望讀者仔細咀嚼。
linux 操作系統的文件構成 內核雖說是linux操作系統的精華所在,是其它程序賴以運行的基礎,但是如果一個實用的操作系統僅僅只有內核,而在其上沒有豐富、強大的系統程序和應用程序供用戶使用,就好比大廈建好了,也通了電,但卻沒有電梯、和辦公設備,用戶仍然無法入住使用。因此linux操作系統的發行版除了帶有內核以外,還帶有大量的系統程序和應用程序,比如紅帽子系統的發行版本句需要2-3張光盤,其中絕大部分是應用程序。 要想深入學習linux內核,首先需要能熟練使用linux操作系統,了解整個系統文件構成——正所謂,刨丁解牛,始見無非全牛者——由外至內的學習linux,再從內向外推敲;從感性深入理性,再由理性返回感性,才會獲得zui深刻的認識。內核的眾多特點zui終還是要反映到用戶應用上的,所以先熟悉應用無疑會對內核學習有很大裨益。而且學習內核結構的一個重要目的就是推動我們更有效的使用linux操作系統,無論是從系統管理角度來說或是從程序開發角度上說,掌握內核級別的系統調用、資源分配、中斷控制或進程調度等技術都是不凡的價值,可以幫助你有效開發和駕馭系統。 這節我們先在這里簡要介紹一下linux系統的文件構成,將linux操作系統的外在全貌展現給大家。我們在系統啟動后,進入系統所能觀察到的就是一系列目錄(使用ls或dir),認識這些目錄構成是學習使用linux系統的*步,下面我們就羅列出主要目錄并簡要描述各自內容。linux系統根目錄/下包含包含:bin:該目錄存放zui常用的基本命令,比如拷貝命令cp、編輯命令vi、刪除命令rm等。boot:該目錄包含了系統啟動需要的配置文件、內核(vmliuxz)和系統鏡像(initrd….img)等。dev:該目錄下存放的是linux中使用或未使用的外部設備文件(fd代表軟盤,hd代表硬盤等),使用這些設備文件可以用操作文件的方式操作設備。 etc:該目錄下包含了所有系統服務和系統管理使用的配置文件;比如系統日志服務的配置文件syslog.conf,系統用戶密碼文件passwd等 home:該目錄下包含了除系統管理員外的所有用戶的主目錄,用戶主目錄一般以用戶登陸帳號命名。 lib:該目錄下包含了系統使用的動態連接庫(*.so)和內核模塊(在modules下)。 host+found:該目錄包含了磁盤掃描檢測到的文件碎片,如果你非法關機,那么下次啟動時系統會進行磁盤掃描,將損壞的碎片存到該目錄下。 mnt:該目錄下包含用戶動態掛載的文件系統。如果要使用光盤,u盤都一般應該將它們安裝到該目錄下的特定位置。 proc:該目錄屬于內存影射的一個虛擬目錄,其中包含了許多系統現場數據,比如進程序數,中斷情況,cpu信息等等,它其中的信息都是動態生成的,不在磁盤中存儲。 root:該目錄是系統管理員(root用戶)的主目錄。 sbin:該目錄下包含系統管理員使用的系統管理命令,比如防火墻設置命令iptable,系統停機命令halt等 tmp:該目錄下包含一些臨時文件。 usr:該目錄下一般來說包含系統發布時自帶的程序(但具體放什么東西,并沒有明確的要求),其中zui值得說明的有三個子目錄 /usr/src :linux內核源代碼就存在這個目錄 /usr/man :linux中命令的幫助文件 /usr/local : 新安裝的應用軟件一般默認在該目錄下 var:該目錄中存放著在不斷擴充著的信息,比如日志文件。 以上就是linux文件系統的原始構成,熟悉它們是應用linux操作系統的前提,希望大家親自打開各目錄看看。搭建linux試驗系統實例 進入后續章節討論的內核前,我們先與讀者一同從頭構架一個試驗操作系統。這樣既有助大家熟悉linux操作系統的組成結構,也會在構建過程中學習介紹一些linux命令和使用技巧,加深理解linux操作系統的運作方式。 實驗系統將在保證實用價值的基礎上,盡量小巧。希望大家通過親手構建系統的過程中,能消除對linux的恐懼感,更希望讀者自己能使用裁減的系統,給自己帶來成就感和學習熱情。*的基礎知識 對于*次接觸linux的朋友,僅僅看下面的內容顯然不能指望學會linux的操作方法和系統行為,建議你去找本系統一點的linux系統教程慢慢咀嚼吧。對于像系統管理員這種大牛,跳過下面內容吧,再高的就去看看新浪體育新聞什么的,別在這瞎轉了:)。 搭建系統過程中將離不開敲擊各種各樣的命令,離不開執行大大小小的shell腳本。而zui整個過程中重要的是理解系統的運行思路,一切活動的指導思想都要圍繞系統運行的步伐,要“順從“系統運行自己和系統運行服務這一指導思想。所以基礎知識也從這幾個角度展開。 不過我們蜻蜓點水,不做深究。 基本命令我們首先介紹一組搭建linux系統需要使用的基本的命令。當登陸到linux系統上后,出現在我們面前的是一個shell?提示符(# 或 $等),該提示符號告訴我們系統已經準備接受命令了,你可以用鍵盤輸入命令行來操作系統了,你輸入的命令將在屏幕上顯示出來,并議回車鍵表述命令輸入結束、發送命令給系統的標志 shell和shell編程 shell是什么? 在你登陸到系統后,系統首先運行的是一個特別的應用程序,它顯示一個提示符號表明系統已經準備好開始接受你的命令了,當你鍵入你要執行的命令后,該應用程序將命令提交給linux系統去處理,然后等處理完畢再把結果返回給你,這之后她又將回到提示狀態,去等待你下次輸入命令。這個特殊的“接待”程序就被稱為shell,其作用相當是一個內核與用戶交流的界面,她周而復始地向內核解釋用戶命令,因此shell又被稱稱為命令解釋器。 shell作為一種應用程序并非只有*一種,目前流行的shell有sh / bash /ksh /tcsh/csh等等,他們其實也就始一個應用程序,你可以使用命令whereis ksh/sh/bash來查看其存在于系統中的具體位置。 有興趣得話,你可以通過命令 echo $shell來觀察系統默認的shell屬于那一種。你也可以在登陸后(使用ctrl+d可以重新登陸)使用chsh來改變選擇使用的shell程序,或干脆直接在默認shell上執行新的shell程序——只要鍵入新shell名字并回車即可,如果想推出新shell,就再執行exit程序。 各種shell程序各有特點,功能也有強又弱,但是相同點都需要能夠執行程序或命令;能夠處理程序或命令的輸入輸出;能夠執行shell腳本。(shell 能執行三種不同概念的文件:1命令指shell程序自己內置的基本命令——如 cd 命令,管道 | 命令 >重定向命令——和以二進制文件形式存在的系統命令——如ls cp等。2 程序指用戶安裝和編譯身成的二進制文件;3腳本指包含邏輯關系的程序和命令序列) shell執行文件需要必要的環境,這些環境包含文件搜索路徑,當前目錄,用戶主目錄,默認編輯器等等(你可以從man shell種獲得這些信息)。這些信息屬于環境變量,可以通過env觀察當前系統默認的環境變量,改變這些變量可以通過:變量=設置(如 path= /opt)命令方式和修改存在于用戶目錄下的相關配置文件(如對bash來說配置文件愛你為~/.bashrc,~/.bash_profile)shell編程 shell編程簡單地講就始講命令序列化后執行,而不用被編譯成二進制可執行文件。這類似于dos下地bat批處理文件。使用shell程序的意義在于,有些任務無法通過現有的命令完成,必須使用一組命令協作才能完成,而且各種命令之間不是簡單的羅列而是按照設定的邏輯關系有機結合。由此可見shell程序需要能夠控制各種命令的執行流,能夠讀寫臨時數據,因此,shell程序存在自己控制語句和變量,而且對其使用也由相關語法。 shell程序,也可以成為shell腳本,以普通的linux文本文件形式存在。可以是用vi等文本編輯器生成,再將其屬性改為可執行即可運行。 比如 touch test 生成文件test chmod u+x test 修改屬性 ./test 保險其間可以再腳本頭先使用#!符號來強制當前shell運行其后的制定shell文件來執行該腳本。 當然shell編程覺非上面說的那樣簡單,想要真正學習shell編程并能使用它可不那么容易。有興趣的朋友可以參看有關資料了解shell編程。 系統服務安裝過linux的朋友一定熟悉安裝過程種系統會提示你選擇何種服務,或安裝完畢使用setup命令也可看到一個配置界面其中包含系統服務配置。系統服務包含一系列形形色色的服務,很多服務選項我們*,或者僅僅聽說過罷了。著很正常,因為服務太多太雜了,很少有人能全部搞清楚這些服務是干什么的。我們這里也不追究所有服務的詳細作用,僅僅從系統運行角度介紹一下這些服務的使用方法。(想知道系統到底有那些服務,試試setup命令吧。) 系統服務程序和普通應用程序或系統命令本質是相同的,都是一些二進制文件。但其運行方式卻有一些自身特點。系統服務多數情況下都處于后臺運行,因此運行結果一般不再屏幕顯示(往往被重新定向到/dev/null中),但是為了安全目的或分析目的,大多記錄都要求保存到相關日志中;另外系統服務程序運行時多需要進行一定配置,比如ftp服務器有用戶訪問權限配置,工作目錄配置,因此需要從配置文件取數據初始化服務程序。zui后就時服務程序很多時隨系統啟動就開始運行,而不需要用戶自己啟動。 由于這些特點系統服務程序的啟動或停止一般都存在相應的shell腳本文件管理,利用這些腳本可以控制服務程序的配置,啟動,日志記錄以及關閉服務和清理臨時文件操作。這樣相比用戶手動操作要方便安全得多。 linux系統中的服務程序運行腳本(啟動或關閉)都存放在目錄/etc/rc.d/init.d下——linux系統的文件組織層次遵循fhs規范,包括腳本位置——比如我們啟動/停止網絡所用的network 等腳本。這些腳本都具有相同的使用方法運行:服務腳本 {start|stop|restart|reload|status}。如果你需要手動啟動或停止某項服務,鍵入/etc/rc.d/init.d/服務腳本名 start|stop 即可,除此方法外也可以利用命令 service服務腳本名 start|stop,它們執行作用相同。 系統服務程序多數情況下隨系統啟動開始運行,系統關閉停止運行,這也正是你開機或關機時為什么能在屏幕上看到一系列的服務啟動[ok] 或服務停止[stop]的原因。那么系統如何啟動和關閉這些服務呢? 談到這里很有必要說一下linux系統運行級別這個問題。所謂運行級別更通俗的講就是系統的行為,每種運行級別都對應一組該級別應用程序。 我們可以使用命令init(后問會說明它) 級別來切換系統的運行級別。一般服務器系統使用級別3,如果需要圖形界面使用5,對于單用戶或嵌入系統使用運行級1即可。 其中級別0和6可以使用來安全停止系統,它們會將除根目錄以外的文件系統卸載,并且以只讀方式重新安裝根文件系統,這樣一來防止了破壞文件系統。 言歸正傳,回到系統服務程序。我們應該能猜到不同的運行級別也對應了不同的系統服務集合。比如運行級別5至少就需要比級別3多啟動x服務器和xfs(字體服務器)等。你可以利用命令chkconfig –list來觀察每個運行級別下的各種系統服務是否允許。顯然級別5開啟的服務zui多,下來是級別3 。總之,功能越強要求服務越多。 下面的啟動部分回告訴大家,系統根文件安裝后,首先尋找init程序并運行它,該程序的任務就是從配置文件確定系統的運行級,并且根據級別啟動相應的服務程序。具體的過程如下 init程序從inittab中獲得系統運行級別x ,后會依次運行/etc/rc.d/rcx.d/中以大寫s開頭的shell腳本來啟動對應的服務。 linux系統啟動的標準流程 對于系統裝載過程我們暫時不做介紹,我們假設內核已經被載入內存并且已經完成了異常表、中斷表、調度程序、時鐘、控制臺、內存等初始化,zui后進行進程管理器的初始化,從此內核可以開始使用真正的進程了。 初始化完成后,內核創建*個進程(初始進程),該進程作為系統的第0號進程,在進程描述符表中由task[0]或init_task表示。該進程進而再創建了一個進程去執行init()函數進行第二階段的初始化操作,而初始進程(init_task)本身則去執行idle循環,可見初始進程在內核初始化后*的作用就是去使用空閑的cpu時間。 第二階段的初始化工作要比前一階段輕松一點,因為現在是由一個真正進程完成它們的,而前一階段都是由“硬件進程”手工去做的。該階段,這個由ini_task創建的新進程需要初始化總線、網絡并啟動系統中的各種系統內核后臺線程,然后再初始化外設、設置文件格式,在這之后,它要為進入系統做zui后的準備——初始化文件系統,安裝根文件,打開/dev/console設備,重定向stdin、stdout和stderr到控制臺,然后搜索文件系統中的init程序,并使用 execve()系統調用加載執行init程序。系統自此進入了用戶態。 init程序接著將依照initab配置文件中的選項依次執行: 1 確定運行級別(1-6) 2 運行rc.sysinit腳本中的的系統服務,如激活交換分區,檢查磁盤,加載硬件模塊等 3 運行規定級別下的服務:/etc/rc.d/rc*.d/下的s打頭的服務,如網絡服務s*network。 4 在串口上運行getty程序,getty打開終端線,并設置模式,然后運行login程序。如果用戶帳號和密碼正確(需要通過/etc/passwd驗證),則進入用戶的工作目錄,并按照其工作目錄中的設置執行相應的shell。 到這里用戶才可以真正實用操作系統了。 idle進程是個奇怪的進程,它是在沒有別的任務使用cpu時是才使用cpu的,它的存在價值據說可以延長cpu壽命。 內核后臺線程是種執行在內核態的進程,它們和用戶進程一樣受調度程序調度,系統利用它們周期性(不一定固定周期)地執行一些自身管理方面的“家務事”。主要的幾種內核線程為:bdflush——清理被寫過的內存緩沖區;kup-date——按時將內存緩沖區中的信息更新到磁盤中; kswapd——將內存頁交換到磁盤;keventd——關系系統事件;ksoftirq——執行軟件中斷。 搭建實驗系統 很抱歉搭建一個linux操作系統到目前為止還沒有一個很標準的流程或規范,不過大體流程都大通小異,無非是首先編譯內核——將內核源代碼編譯成一個可執行的鏡像文件,當然編譯內核時可能會帶有一些模塊也需要同期進行編譯和安裝(是否有模塊取決于你的具體選擇)。 有了編譯后的內核,接著就需要創建一個根文件系統,在其中又需要創建必要的目錄。至于其中使用的軟件和庫函數你可以選擇下載源代碼包,然后交叉編譯,再進行安裝。或者我們偷個懶,從一個發布的完整系統里直接拷貝需要的軟件和庫,同時將必要的設備文件、配置文件和服務腳本也拷貝過來,你這時所要做得僅僅是去修改一些相關的配置文件就可以擁有一個自己的文件系統了。 內核與文件系統都有了,就可以說一切具備只欠東風,你所需要做得只剩下將內核和文件系統綁定到一起,讓系統被引導載入內核,內核載入后可以找到根文件系統,并執行其中的初始化程序。你可別以為這個收尾動作能輕松搞定,往往初學者都在這里要栽跟頭。 怎么能在zui小的代價學習搭建系統呢?想想看可不是每個網友都能找個空硬盤或者磁盤(看看你的機器,也許連軟驅都沒)來做新系統的,為了保護原有系統,即便開一個新分區都不能鼓勵。所以的方法就是用內存模擬一個磁盤,將創建的根文件系統放在其中,系統引導后,就登陸到內存模擬的磁盤上運行。這時你*跳出了你的物理硬盤。這種方法有時在嵌入系統中會被使用,或希望斷電后數據被抹掉的安全系統中使用。 下面我們就一同做個這樣的試驗系統,你付出的*代價是消耗些時間和無數次擊健。編譯內核 *步要做的工作就是挑選一個合適版本的內核源代碼包,然后編譯它。不要以為編譯內核很神秘,其實它和編譯普通程序差不多,內核源代碼其實就是“一大堆”程序,編譯它就等于分別編譯個個程序然后在將它們鏈接成一個單一的可執行鏡像文件。這個鏡像就是你在/boot目錄下看到的vmlinuz-*(如果你細心的話,一定能發現在該目錄下還有一個叫vmlinux的文件。其實這兩個文件是一回事,但前面那個是經過壓縮的) 正如*部分所說,linux內核具有很強的伸縮性,在內核里面許多功能是可選擇的,如果需要就可以被編譯到內核,不過內核會因此變的肥胖。一種可替代的方式是將某些功能編譯成模塊放在文件系統內,等你真正需要它時,再由被載入到內核,這樣就內核就可以輕裝上陣了,啟動起來也快許多。 雖然是個試驗系統,但還是盡力讓它功能做強點吧。所以在編譯前,配置內核選項時,除了支持zui基本的ext2文件系統,pci接口,自動裝在模塊等功能外,再將ext3,jfs,即插即用,網絡,scsi,usb等比較常用的功能加入。再一個就是為了能實現我們的虛擬內存中建立根文件系統,內核還需要支持ramdisk 和initrd。內核網絡設備選項里包含大量網卡驅動程序,你必須知道自己網卡內型才能正確選擇,一般情況都將網卡驅動編譯未模塊,在系統啟動后載入。我們試驗系統運行在vmware下,而vmware虛擬網卡驅動為pcnet32,因此這個模塊被包含進來了。編譯步驟 先去下載一個內核源代買不用我在多說了吧。如果你實在是個衣來伸手的家伙,好吧告訴你,到上蕩一個想要版本的內核源代碼。如果是gz結尾的壓縮源文件,就使用tar xvzf linux-2.4.18.tar.gz解開,如果是gz2結尾的,就使用tar xvjf linux-2.4.18.tar.bz2解開。 內核版本編號可是有點講究的,簡單的說,偶數為穩定版本,奇數為開發版本,所以我們用2.4.18版,一是因為它屬于穩定版,再一個就使我機器里以前下載過它,不想再換了:)。 然后進入存放解開后的內核原代碼的目錄(標準系統默認情況下在目錄/usr/src/linux下存放該系統的內核源代碼),執行命令make menuconfig進行內核功能配置,選擇需要的功能以模塊形式編譯或直接編譯到內核。配置信息默認情況下記錄在隱含文件.config中,你也可以選擇將其記錄到自定義文件中,比如可以把信息記錄在minisys.config中。在以后配置內核時可以方便地導入的配置文件。
附件——linux系統啟動的標準流程 系統的啟動是指從計算機加電到顯示用戶登陸提示的整個過程。我們將在這里對整個流程以及關系到的一 些內容做討論。過程主要可以分為兩個階段:載入內核和準備運行環境,我們分別進行討論。本部分的 討論只基于i386硬 件架構,但大部分內容是有共通性的。
圖一 啟動過程 綜述 載入內核(將內核載入內存,并將控制權傳遞給它) 計算機加電到boot loader開始工作,硬件含量 遠大于軟件含量,所以這里暫不提及,如果實在有關心的朋友,請先別著急,我們將在下期里討論它。 這一階段是 boot loader 的主戰場。它必須將可執行的內核映像和內核啟動所需的額外數據信息從存儲介質上載入內存,這并不是 件簡單的工作,因為除了從硬盤載入,可能還會需要從網絡引導服務器這樣的外部介質上載入。各種紛繁蕪雜的文件系統類型也給載入帶來了巨大的挑戰。 boot loader 可能還需要改變cpu的運行特權級別,然后就可以讓內核投 入運行了。 除此之外,boot loader 還要完成一些其它功能,比如從bios中獲取系統信息,或者從啟動時的命令行參數中提取信息等。有的 boot loader 還要扮演引導選擇工具的角色,方便用戶選擇不同的操作系 統。 boot loader的職責: 判斷到底要載入什么,這可以要求用戶進行選擇 載入內核和它可能需要用到的相關數據,比如initrd或者其它參數 為內核準備好運行環境,比如,讓cpu進入特權模式 讓內核投入運行 boot loader的 歷史變遷: 早期的linux只支持軟盤引導扇區和 shoelace 兩種 boot loader。 shoelace 是從minix繼承下來的、對文件系統相關的 boot loader。它只支持 minix 文件系統。當時linux只使用 minix 一種文件 系統,所以這樣做并沒什么問題。可是, minix 文件系統存在不能保存創建、修改和訪問時間信息;文件名長度限制在14個字節等問題。隨著linux的發展,這些與傳統unix文件系統大相徑庭的缺陷越來越讓人 難以忍受,它已經不適合作為linux的主要文件系統了。 為了支持其它文件系統的實現,linux引入了vfs(虛擬文件系統)。這個舉措很快就引起了熱烈的反響,一大批新的文件系統實現出現了。其中一個 minix 文件系統的變體,擴展文件系統 xiafs (根據它的作者命名)突破了 minix 文件系統的文件名長度限制,將此長度一舉提高到全部30個字符。當時文件系統之間的競爭著實激 烈,很難看出誰會勝出,甚至搞不清楚會不會有一個zui終的“贏家”。 盡管不確定性很大,但是有一點卻是清楚的:不管zui后哪種文 件系統會受到青睞,但是除了 minix 作為根文件系統,誰也不能從硬盤上啟動,因為 shoelace 只支持minix文件系統。lilo應運而生了。由于支持多種文件系統(當時內核支持的主流文件系統已經有 minix ,擴展文件系統 ext , xiafs 。還有人在移植 bsd 的 ffs ,根本看不出來什么時候是個盡頭)在實現和維護上難度太大,而 boot loader 也不 應該成為人們試驗新的文件系統的絆腳石,所以lilo采取了和文件系統無關的設計。 這種設計經受住了時間的考驗,被證明是非常成功的。即使在今天,lilo仍舊可以從內核支持的絕大部分文件 系統的硬盤上啟動。但是,由于ext2歷經這么長的時間一直沒有大的演變,成為了事實上的標準,所以跟文件系統相關的boot loader又漸漸流行了起來。盡管ext2已經能滿足大部分人的日常需要,但 是文件系統的設計者們還是在研制以日志機制為特征的新的文件系統,并且已經取得了相當大的進展。考慮到當前又有可能出現多種文件系統的實現同時并存的情 況,因此對與文件系統無關的boot loader的需求可能會再次變得強勁。初始化基本的操作環境 一旦內核開始運行,它會初始化內部的數據結構,檢測硬件,并且激活相應的驅動程序,為應用軟件的準 備運行環境。其間包含一個重要操作——應用軟件的運行環境必須要有一個文件系統,所以內核必須首先裝載root文件系統。由于我們的目的是介紹基 本流程,所以相關的硬件初始化細節就不再討論,相關內容在下一期雜志中會有詳細介紹。 硬件初始化完成后,內核著手創建*個進程——初始進程。說是創建, 其實也不盡然,該進程其實是整個硬件上電初始化過程的延續,只不過執行到這里,進程的邏輯已經完備,所以我們就按照進程的創建方式給它進行了“規格化” ——我們把這個初始進程也叫做“硬件進程”,它會占據進程描述符表的*個位置,所以可以用task[0]?或init_task表示。該進程進而會再創建一 個新進程去執行init()函數,其實,這個新進程才是系統*個實際有用的進程,它會負責接著執行下一個階段的初始化操作; 而初始進程(init_task)自己則會開始執行idle循環,也就是說,內核初始化完成之后,初始進程*的任務就是在沒有任何其它進程需要執行的時候, 消耗空閑的cpu時 間(因此初始進程也被稱為idle進程)。 下一階段的初始化工作要比前一階段輕松一點,因為現在是由一個真正進程接手負責完成它們了,而前一 階段都是由“硬件進程”手工去做的。在此階段,這個由init_task創建的新進程需要初始化總線、網絡并啟動系統中的各種系統內核后臺線程,然后再初始化外設、設置文 件格式,在這之后,它要為進入系統做zui后的準備——初始化文件系統,安裝root文件系統,打開/dev/console設備,重定向stdin、stdout和stderr到控制臺,然后 搜索文件系統中的init程序,并使用 execve()系統調 用加載執行init程 序。系統自此進入了用戶態。裝載root文件系統 為了裝載文件系統,內核需要:1知道root文件系統位于那個存儲介質上;2有訪問該種介質的驅動程序。zui常見的情況是root是ext2文件系統,位于ide硬盤上。這種情況下需要的操作很簡單:將設備號作為參數給內核就可以了,ide的設備驅動程序通常都會編譯進內核 的。 如果內核沒有相關介質的驅動程序,問題就會變得更為復雜。而這種情況并不罕見,比如linux的安裝盤使用的“通用”內核一般都會碰到。如果內核把所有支持的硬件的設備驅動程序都包含進來,就會變成一個龐然 大物;而且一些驅動程序在檢測硬件的時候會影響其它設備。 這個問題可以通過initrd機制解決,它允 許在裝載實際的root文件系統之前先使用ram文件系統。除了上述兩個原因,引入initrd還可以解決內核 的動態合成問題。(詳見參考資料一。) 不過我們應該注意到,init在整個啟動過程中并不是從來就有的,它可以說是一個插件,為了解決以上問題,而被加入啟動過程,象圖一所示,linux系統在啟動時也可以不選擇它。為什么要引入initrd? linux啟動過程中肯定要載入內核鏡像,在此過程中有些要素必須考慮: 首先,內核鏡像不能太大。由于受到各種硬件和兼容性的限制,linux的內核鏡像不能太大,但是這并不 容易做到。linux內核的核心部分本身就不小了;而且還必須加入會使用到的驅動程序。 其次,要支持盡可能多的硬件設備。我們在啟動過程中有一件重要工作:掛載root文件系統,因為進一步的數據和應用 軟件都在其上,所以我們的內核必須能夠訪問root文件系統。對于一般用戶,如果他們使用ide硬盤上的ext2文件分區作為root文件系統,不會有什么問題。因為不管是ide硬盤還是ext2文件系統,它們的驅動肯定會包含在內核鏡像自身里面。但是,確實存在一些特殊情況:比如說我們希望 發行linux系 統的安裝光盤,那么對光盤的驅動,就不一定包含在內核里面了。(有人可能要奇怪了,咦,光盤中的內核鏡像不都已經讀進來了嗎,怎么內核還訪問不了光盤呢? 注意,讀入內核鏡像的是 boot loader ,內核并不具備 boot loader 的功能。)如果沒有光盤的驅動,我們又怎么把光盤里的軟件包安裝到用戶的 計算機里呢?把驅動程序預先編譯到內核里?聽起來還不錯,可是如果我們除了光盤還有一些其它的安裝介質,那么所有這些驅動就會讓內核鏡像龐大不堪。 而且,還有更嚴重的問題,各種不同的驅動程序很有可能會發生沖突,特別是以前isa設備占市場主導地位的時候,這種沖突 簡直難以避免。 那時的解決辦法是發行商提供預先編譯好的支持各種設備的不同內核,把每個內核放進一張軟盤,隨發行 包一起交給用戶,用戶自己選擇裝有合適內核的軟盤進行引導。或者給用戶提供制作引導盤的工具,讓用戶在安裝前制作自己的啟動盤。當然,哪一種辦法都不能讓 人滿意。 *的希望在于使用模塊化機制。在內核啟動的時候調用相應的模塊加載驅動程序,然后訪問root文件系統。無論是通過內核對設備做 進一步的分析還是直接從用戶那里得到配置信息,先配置再加載模塊的辦法,都能有效地避免沖突的發生。 除了在安裝的時候需要在掛載root文件系統之前調用相應的模塊之外,在完成安裝的系統上,我們可能仍然需要在掛載root文件系統之前調用一些模塊。這主要 是為給計算機進行配置——一般都要針對不同的計算機進行內核配置。 理想情況下,用戶按照自己的實際情況配置編譯文件,重新編譯內核,一步步完成這種工作。但是沒有幾個用戶喜歡這種冗長并且極易出現錯誤的工作。而且編譯和生成內核需要相應的 工具,可是大部分用戶不需要這些工具。 在安裝的過程中可以直接編譯一個整體式的內核,但這并不能很好的解決問題:首先,所有的編譯工具還 需要,其次,編譯過程中出現差錯導致無法完成任務的概率太大了。所以,我們仍然要使用模塊機制:模塊機制很可靠,出了錯誤也只不過不加載對應的模塊而已,不會使整個任務失敗。而載入模塊,象前 面說的,也是在掛載root文件系統之前就要得到模塊的。 基于以上理由,linux引入了initrd機制。initrd做什么 initrd允許系統在啟動 的時候載入一個ram盤,這個ram盤可以被當作一個root文件系統,程序可以在其上運行。(有兩重含義,*,程序在上面;第二,程序的文件系統環境也在上 面。)在此之后,可以從別的設備上掛載一個新的root文件系統,先前的root文件系統(initrd)就會被移動到 一個目錄上去,zui終被卸載掉。 為什么要使用ram盤呢?首先,使用ram盤能方便的支持以后可能發生的變化;另外,也是為了保持 boot loader 工作盡可能的簡 單。在系統引導時,除了內核鏡像之外,boot loader把所有相關的信息作為一個文件讀入內存,內核在啟動中將該文件作為一段連續的內存塊看待。也就是把 它當作ram盤來 使用了。正因為如此,這種機制被稱作“初始 ram 盤 (initial ram disk)”,縮 寫成 initrd。 initrd主要用來把系統 的啟動劃分為兩個階段:初始啟動的內核只需保留zui精簡的驅動程序zui小集,此后,在啟動必須加載附加的模塊時,從initrd中加載。 initrd進行的操作 使用initrd的時候,典型的 系統啟動的流程變為:boot loader讀入內核鏡像以及initrd文件內核將initrd文件轉成“普通”的ram盤,并且釋放掉initrd文件占用的內 存。initrd被當作root文件系統,以可讀可寫(read-write)方式安裝。/linuxrc被執行 (它可以是任何可執行文件,包括腳本在內;它以uid0身份執行,基本上能完成所有init程序可以做的工作)linuxrc安裝“實際” 的root文件系 統linuxrc通過pivot_root系統調用將root文件系統放置在root目錄下。常用的啟動流 程(比如調用/sbin/init)開始執行。卸載initrd文件系統。 注意,這是一個典型流程。其實initrd機制可以通過兩 種方式使用:要么就是作為一個普通的root文件系統使用,這樣的話第5、第6兩個步驟可以被略過,直接執行/sbin/init(我 們的試驗系統就是利用這種方法);要么作為一個過渡環境使用,通過它內核可以繼續裝載“實際”的root文件系統。
免責聲明
- 凡本網注明"來源:智能制造網"的所有作品,版權均屬于智能制造網,轉載請必須注明智能制造網,http://www.xashilian.com。違反者本網將追究相關法律責任。
- 企業發布的公司新聞、技術文章、資料下載等內容,如涉及侵權、違規遭投訴的,一律由發布企業自行承擔責任,本網有權刪除內容并追溯責任。
- 本網轉載并注明自其它來源的作品,目的在于傳遞更多信息,并不代表本網贊同其觀點或證實其內容的真實性,不承擔此類作品侵權行為的直接責任及連帶責任。其他媒體、網站或個人從本網轉載時,必須保留本網注明的作品來源,并自負版權等法律責任。
- 如涉及作品內容、版權等問題,請在作品發表之日起一周內與本網聯系,否則視為放棄相關權利。
2025長三角國際智能儀表/線纜產業博覽會
展會城市:滁州市展會時間:2025-11-11