1、關於內核原始碼樹
目錄 |
描述 |
arch |
特定體系結構的原始碼 |
block |
塊裝置I/O層 |
crypto |
加密API |
Documentation |
內核原始碼文件 |
drivers |
裝置驅動程式 |
firmware |
使用某些驅動程式而需要的裝置韌體 |
fs |
VFS和各種檔案系統 |
include |
內核標頭檔案 |
init |
內核引導和初始化 |
ipc |
進程間通訊程式碼 |
kernel |
像排程程式這樣的核心子系統 |
lib |
通用內核函數 |
mm |
記憶體管理子系統和VM |
net |
網路子系統 |
samples |
範例,示範程式碼 |
scripts |
編譯內核所需的指令碼 |
security |
Linux安全模組 |
sound |
語音子系統 |
usr |
早期使用者空間程式碼(所謂的initramfs) |
tools |
在Linux開發中有用的工具 |
virt |
虛擬化基礎結構 |
2、關於內核開發的特點
1)內核程式設計時既不用存取C庫,也不能存取標準的C檔案;
2)內核程式設計時必須使用GNU C;
3)內核程式設計時缺乏像使用者空間那樣的內核保護機制 機製;
4)內核程式設計時難以執行浮點運算;
5)內核給每個進程只有一個很小的定長堆疊;
6)由於內核支援非同步中斷、搶佔和SMP,因此必須時刻注意同步和併發。
3、關於標準C函數庫
- 與使用者空間的應用程式不同,內核不能鏈接使用標準C函數庫。最主要的原因時速度和大小。對內核來說,完整的C庫——哪怕是它的一個子集,都太大且太低效了。
- 不過不用擔心,大部分常用的C庫函數在內核中都已經得到了實現。
- 內核程式碼雖然無法呼叫printf(),但它提供了printfk()函數,幾乎與printf()相同。
4、關於GNU C
- gcc是多種GNU編譯器的集合,它包含的C編譯器既可以編譯內核,也可以編譯Linux系統上用C語言寫的其它程式碼。
- 內核開發者使用的C語言涵蓋了ISO C99標準和GNU C擴張特性。Linux內核使用gcc的各種特性。
- 當我定義一個內函數時,需要使用static作爲關鍵字,並且用inline限定它。比如:
static inline void wolf(unsigned long tail_size)
。由於使用了static作爲關鍵字進行限制,所以編譯時不會爲行內函式單獨建立一個函數體。在內核中,爲了型別安全和易讀性,優先選用行內函式,而不是複雜的宏。
- 對於內聯彙編,我們通常使用asm()指令嵌入彙編程式碼。在偏近體系結構的底層或對執行時間要求嚴格的地方,一般使用的是彙編語言。而內核其它部分的大部分程式碼是用C語言編寫的。
- 對於條件選擇語句,gcc內建了一條指令用於優化,在一條條件經常出現,或者該條件很少出現的時候,編譯器可以根據這條指令對條件分支選擇進行優化。內核把這條指令封裝成了宏,比如
likely()
和unlikely()
。還有,必須明確的一點是,如果你判斷正確,確實是這條佔壓倒性的地位,那麼效能會得到提升;如何搞錯,效能反而下降。
5、關於記憶體保護機制 機製
- 如果一個使用者程式試圖進行一次非法的記憶體存取,內核就會發現這個錯誤,發送SIGSEGV信號,並結束整個進程。
- 對於內核,自己非法訪問了記憶體,則後果很難控制(使用者空間的非法存取,可以由內核來處理,而內核的存取,由誰來管呢?)。內核發生的記憶體錯誤會導致oops,這是內核中出現的最常見的一型別錯誤。
- 在內核中,不應該做存取非法的記憶體地址,參照空指針之類的事情,否則它可能會死掉卻根本不告訴你一聲——在內核裡,風險常常比外面更大一些。
6、關於浮點數
- 與使用者空間進程不同,內核並不能完美地支援浮點操作,因爲它本身不能陷入。陷入指觸發中斷。
- 在內核中使用浮點數是,除了要人工儲存和恢復浮點暫存器,還有其它一些瑣碎的事情要做。
- 在內核中,不要輕易使用浮點數。
7、關於內核棧
- 內核棧的準確大小隨體系結構而變。在X86上,棧的大小在編譯時設定,可以是4KB,也可以是8KB。
- 從歷史上說,內核棧的大小是兩頁,這意味着,32位元機的內核棧是8KB,而64位元機是16KB,這是固定不變的。每個處理器都有自己的棧。
8、關於同步和併發
- 內核很容易產生競爭條件。和單執行緒的使用者空間程式不同,內核的許多特性都要能夠併發地存取共用數據,這就要求有同步機制 機製以保證不出現競爭條件。
- 常用的解決競爭的辦法是自旋鎖和號志。