人們常常說作業系統這個名詞啊,Windows\Linux\MacOS可以說是世間三大巨頭了。小衆的我們就不說了。
我們一般在生活中隻能感受到應用層,像你打開微信等操作就是來自此次,當然你也可以直接操作螢幕,按鍵等硬體,但其實這些還是由作業系統進行管理,才能正常被使用的。
簡而言之,作業系統就做兩件事情。
- 對于整個計算機系統的軟硬體資源進行管理
- 給使用者提供服務
我們這些核心開發人員每次都在強調有什麼最優解決方案。側面說明了作業系統的目标就2個,一個是提高資源的使用率,另一個可不就是為了友善使用者使用嘛~~
歡迎各位大牛來指正!!
1、Linux的整體結構
其實Linux的結構也非常簡單,一般呢,我們将其分為使用者空間與核心空間。大體上就如圖所示喽。

當一個應用發起請求,其實是在給系統調用請求,然後作業系統根據系統調用請求,提供相應的服務。
在這裡一定要有個概念,即計算機上作業系統中的核心設計理念--機制與政策分離。
機制即提供什麼功能,政策則是如何使用這些功能。這裡也就明白了這邊的機制與政策的隔離,用什麼,不就是我們這邊的系統調用嘛,那麼多應用可都是調用同一個系統調用接口的。
2、單核心與微核心
Linux就是一個單核心(又稱宏核心)結構,所謂單核心就是作業系統的各個子系統(後續準備寫一系列Linux子系統的文章,督催自己學習的同時,分享給大家)可以直接互相調用,而微核心的概念就核心的程序間的通信中斷排程等放在微核心中,而其他像檔案系統,記憶體管理等是以伺服器的方式放在外面。
單核心性能高,直接可以調用接口,但是它的維護性差。
微核心呢由于它需要和伺服器進行通信,那麼性能差不可避免,但是維護性好啊,最具代表性的就是谷歌的Fuchsia作業系統。
Linux可維護性差? 這時有人問了,差在哪裡?那麼告訴你如果你想加一個驅動,需要每次都編譯Linux核心,而且它現在越來越大了,編譯會變得很慢,而且冗雜在一起的代碼,你不覺得可維護性比較差嗎?
為解決這個問題,提出了可加載的Linux核心子產品(LKM)。哎,好熟悉啊。這個呢,其實就是moduel加載。這裡我們不詳細叙述,後面的文章介紹驅動加載方面的知識的時候,再做分析。
3、程序概述與記憶體概述
運作在作業系統上的應用程式、服務及其他程式都被稱為程序。由于Linux是多任務的系統,看上去是多任務并發的,其實真正正在運作的程式數量最多不過是CPU數目,原因是你所看到的各種程序是CPU不斷在不同的程序間進行切換,是以感覺不出來罷了。
一般核心啟動第一個進行init程序為第一個程序,作為1号父程序,其他的每個程序依賴于它。
我們可以用pstree指令看到程序樹
# pstree -p init(1)---sh(243)---pstree(346)
在linux中建立程序有兩個函數:fork與exec。
除了重量級程序還有輕量級的子程序--線程,簡而言之,程序可以看做是正在執行的程式,而線程則是與程序并行運作的程式函數與例程。在linux裡面是使用clone方法建立線程,有關程序這塊的具體排程,還是要出一版專題去讨論它。
我們再從程序角度看待整個位址空間的話,對于任何程序來講,它隻有一個位址空間,無法感覺到别的程序,這就是我們常說的虛拟位址空間,為什麼說他是虛拟呢,很簡單,因為Linux将其分為核心空間與使用者空間。
但在由于64位的系統為了優化CPU的工作量,可能使用的位址空間位數小于64位,是以上圖中的簡單劃分不一定是完全正确。
那麼如何能讓虛拟位址與實際實體位址聯系在一起呢,這需要将實體位址空間映射到虛拟位址空間去。Linux在這方面就是用頁來表示的。而用來将虛拟位址空間映射到實體位址空間的資料結構稱為頁表。大家都知道記憶體是很大的,為每頁都配置設定頁表,這種情況很糟糕,因而産生了多級分頁。Linux一般采用4級分頁,PGD全局頁目錄;PMD中間頁目錄;PTE頁表數組,然後再offset才能找到位址。
可以看到為了找到相應的位址,需要跨這麼多數組清單,這影響效率啊,為了試圖解決這個問題,CPU一般專門會有MMU與TLB。MMU優化記憶體通路操作,TLB是直接将通路最頻繁的位址儲存起來,然後直接通路即可。
在核心中,我們知道配置設定記憶體的時候,你必須先标記這個頁幀(實體位址記憶體頁)已配置設定或是空閑狀态。為了更加快速檢測記憶體的連續區域,核心采用了一個方案,叫夥伴系統,其實非常簡單了解,就是記憶體中的連續的記憶體庫,可以單獨配置設定,當空閑的時候呢,兩個連續的記憶體變成更大的記憶體塊,作為下一次記憶體塊的夥伴。
而核心還有可能要用到更小塊的記憶體的時候,此時會用到在夥伴系統之上的一個記憶體管理層,我們稱其為slab緩存,一般它可以用兩種方法配置設定記憶體。一個是對于頻繁使用的對象,核心會隻定義對象執行個體緩存,slab自動與夥伴系統互動,并完成緩存用完後自動申請頁幀。而另外一種就是我們常常在核心中使用的kmalloc和kfree。
4、系統調用
在linux的應用程式設計中,更多的開發者們一般調用POSIX标準定義的系統調用。一般我們将其分為
* 程序管理
* 信号
* 檔案
* 目錄和檔案系統
* 保護機制
* 定時器函數
在系統調用這塊,其實可以從一個小的ioctl的深入到核心的各個内部子產品。還有BSD的套接字的抽象使用。檔案系統的各類調用。這些在我的博文中應該不會講的過于的多,後續會對網絡的套接字做一份有關系統調用到最底下實作的文章。
5、後記
說實話,linux核心是一個非常有意思的東西,我們常聽說C# C++等都是面向對象程式設計,而linux核心有嗎?其實有的,如果你細心關注過kobject.h,就是将核心抽象化的。還有一些類似于類型定義,數組對齊,位元組對齊等等,絕對是值得深思的一些代碼。