天天看點

UNIX核心(5):核心開發的特點

原文轉自:http://blog.chinaunix.net/uid-7471615-id-83765.html

核心開發不是洪水猛獸。一旦你了解到其中的規則,你就會發現,跟開發應用程式一樣;兩者差別在于要遵守的規則集合不一樣。

Linux是UNIX家族的一員,而且其核心源代碼唾手可得,是以這裡用其來作說明。

規則上,與應用程式(運作于使用者空間)的開發不同,主要表現在:

沒有C庫

用GNU C程式設計(對于Linux核心而言)

沒有記憶體保護

在核心中很難使用浮點數

核心棧大小固定且很小

由于異步中斷、搶占以及支援SMP,需要額外小心同步和并發

移植性問題

下面就來逐個解釋。

核心沒有連結任何C庫。這裡面涉及到很多問題,比如雞生蛋還是蛋生雞的問題:因為C庫都會包裹一些系統調用,可是沒有核心時就沒有系統調用,那麼……呵呵,明白了吧?另一個問題就是大小問題。任何一個C庫,甚至其一個子集,對于核心來說都太大了。不過,不要着急,很多常用的庫函數在核心中都有實作。

這裡面涉及到一個著名的函數:printf(),核心提供了一個替代品:printk()。如果你要做核心開發,就會頻繁使用該函數。記住:Linus本人不允許在核心中嵌入調試器(這是另外的話題,有興趣的可以自己去google一下),是以很多情況下要依靠printk()。

毫無疑問,Linux的核心是用C語言寫的。但所用的C并不是ANSI C,而是經過GNU擴充之後的C,這就是為什麼Linux核心對于gcc編譯器的依賴程度如此之高。GNU對C的擴充中就包括:内聯函數(inline functions),分支預測和内聯彙編(inline assembly)。分支預測用于判斷哪些情況是幾乎永遠不可能發生的,或者哪些情況幾乎永遠都會發生——unlikely()和likely()。

當使用者空間的代碼通路非法位址時,核心能夠捕獲該錯誤,然後向程序發送SIGSEGV并終止程序。在UNIX世界,人們總是說kill/殺掉程序,其實,kill僅僅是用來向程序發送信号的,并不是殺掉它——太殘忍了。這是題外話了,呵呵。那麼,當核心代碼通路非法位址時,誰來照顧核心呢?隻能自己照顧自己了。非法的位址通路将導緻oops,這是重大的問題,沒人會告訴你通路了非法位址,但是你可以通過日志來查詢/調試。

另外,核心記憶體是不分頁,是以你沒申請一個位元組,實體記憶體就少掉一個位元組。小心了!

在核心中使用浮點數非常困難,如果你想給自己找麻煩的話,可以試試。使用者空間代碼要使用浮點數指令時,一般來說會産生一個中斷,核心捕獲該中斷并作相應的處理。然而,核心沒法捕獲自己。而且,要使用浮點指令,不但要儲存浮點寄存器,還要做很多繁瑣的事情——光看看核心如何為使用者空間代碼使用浮點數就知道了,可以參考程序排程裡的上下文切換。

使用者空間的程式可以在棧上申請大量的空間——定義足夠多的局部變量,因為使用者空間的棧非常大,而且可以動态增長。不過有些不夠智能的系統做不到動态增長。然而,核心的棧非常小,而且無法動态增長。

作為一個搶占式多任務、支援對稱多處理(SMP)的系統,同步和并發是任何一個核心hacker都需要時時刻刻小心的問題。排程器“興之所至”,排程程序,這就需要同步;加上來自CPU外的各種中斷導緻核心需要對某些代碼或資料加以保護。而搶占的意思就是,無論誰占用了CPU,都有可能被其他程序搶掉,核心也不例外。Linux對于競态條件提供了spinlock(自旋鎖)和semaphore(信号量)。

最後就是移植性問題。這個問題從來都不見簡單,而且linux的目标是多種平台都能運作,是以移植性顯得更為重要。位元組序問題就是一個典型的移植性問題。然而,應用程式可能僅僅為一個平台開發。

看了這些,是不是覺得,其實核心開發也不難呢?

有雄心的hacker們,不要被OS kernel這個名詞吓倒。看看Linux Kernel Development,準備好Linux核心源碼,沏上一杯茶,然後你就可以開發核心了!

參考:

Linux Kernel Development, 2nd edition, by Robert Love

Copyleft (C) 2007 raof01. 本文可以用于除商業用途外的所有用途。若要用于商業用途,請與作者聯系。

繼續閱讀