Linux 實時技術與典型實現分析

本系列文章分兩部分,第 1 部分闡述了實時的概念、衡量實時性的指標,詳細地分析了嵌入式系統對 Linux 實時性的需求以及 Linux 在實時性方面的不足,然後簡單地描述了三個著名的 Linux 實時實現,第 2 部分對一個典型的實時實現(Ingo's RT patch)做了詳盡的分析。

一、實時的概念

所謂實時,就是一個特定任務的執行時間必須是確定的,可預測的,並且在任何情況下都能保證任務的時限(最大執行時間限制)。實時又分軟實時和硬實時,所謂軟實時,就是對任務執行時限的要求不那麼嚴苛,即使在一些情況下不能滿足時限要求,也不會對系統本身產生致命影響,例如,媒體播放系統就是軟實時的,它需要系統能夠在1秒鐘播放24幀,但是即使在一些嚴重負載的情況下不能在1秒鐘內處理24幀,也是可以接受的。所謂硬實時,就是對任務的執行時限的要求非常嚴格,無論在什麼情況下,任務的執行實現必須得到絕對保證,否則將產生災難性後果,例如,飛行器自動駕駛和導航系統就是硬實時的,它必須要求系統能在限定的時限內完成特定的任務,否則將導致重大事故,如碰撞或爆炸等。

二、衡量實時性的指標

那麼,如何判斷一個系統是否是實時的呢?主要有以下兩個指標:

1. 中斷延遲

中斷延遲就是從一個外部事件發生到相應的中斷處理函數的第一條指令開始執行所需要的時間。很多實時任務是靠中斷驅動的,而且中斷事件必須在限定的時限內處理,否則將產生災難性後果,因此中斷延遲對於實時系統來說,是一個非常重要的指標。

2. 搶佔延遲

有時也稱調度延遲,搶佔延遲就是從一個外部事件發生到相應的處理該事件的任務的第一條命令開始執行的時間。大多數實時系統都是處理一些週期性的或非週期性的重複事件,事件產生的頻度就確定了任務的執行時限,因此每次事件發生時,相應的處理任務必須及時響應處理,否則將無法滿足時限。搶佔延遲就反映了系統的響應及時程度。

如果以上兩個指標是確定的,可預測的,那麼就可以說系統是實時的。

三、影響系統實時性的因素

對系統實時性的影響因素既有硬件方面的,也有軟件方面的。

現代的高性能的硬件都使用了cache技術來彌補CPU和內存間的性能差距,但是cache卻嚴重地影響着實時性,指令或數據在cache中的執行時間和指令或數據不在cache中的執行時間差距是非常巨大的,可能差幾個數量級,因此爲了保證執行時間的確定性和可預測性,來滿足實時需要,一些系統就失效了cache或使用沒有cache的CPU。

另一個硬件方面的影響因素就是虛存管理,對於多用戶多任務的操作系統,它確實非常有用,它使得系統能夠執行比物理內存更大的任務,而且各任務互不影響,完全有自己的獨立的地址空間。但是虛存管理的缺頁機制嚴重地影響了任務執行時間的可預測性和確定性,任務執行時使用缺頁機制調入訪問的指令或數據和被執行的指令和數據已經在內存中需要的執行時間的差距是非常大的。因此一些實時系統就不使用虛存技術,例如 Wind River的VxWorks。

在軟件方面,影響因素包括關中斷、不可搶佔、一些O(n)的算法。

前面已經提到,中斷延遲是衡量系統實時性的一個重要指標。關中斷就導致了中斷無法被響應,增加了中斷延遲。

前面提到的搶佔延遲也是衡量系統實時性的重要指標。如果發生實時事件時系統是不可搶佔的,搶佔延遲就會增加。

還有就是一些時間複雜度爲O(n)的算法也影響了執行時間的不確定性,例如任務調度算法,要想執行實時任務必須進行調度,如果調度算法的執行時間取決於當前系統運行的任務數,那麼調度實時任務所花費的時間就是不確定的,因爲它是與系統運行的任務數呈線性關係的函數,運行的任務越多,時間就越長。

四、嵌入式系統需要實時Linux

Linux在設計之初沒有對實時性進行任何考慮,因此非實時性絕非偶然。Linus考慮的是資源共享,吞吐率最大化。但是隨着Linux的快速發展,它的應用已經遠遠超出了Linus自己的想象。Linux的開放性已經對很多種架構的支持使得它在嵌入式系統中得到了廣泛的應用,但是許多嵌入式系統的實時性要求使得Linux在嵌入式領域的應用受到了一定的障礙,因此人們要求Linux需要實時性的呼聲越來越高。

Linux的開放性和低成本是實時Linux發展的優勢,越來越多的研究機構和商業團體開展了實時Linux的研究與開發,其中最著名的就是FSMLab的Rtlinux和TimeSys Linux。還有一個就是Ingo's RT patch。

五、標準Linux內核制約實時性的因素

標準Linux有幾個機制嚴重地影響了實時性。

1.內核不可搶佔

在Linux 2.4和以前的版本,內核是不可搶佔的,也就是說,如果當前任務運行在內核態,即使當前有更緊急的任務需要運行,當前任務也不能被搶佔。因此那個緊急任務必須等到當前任務執行完內核態的操作返回用戶態後或當前任務因需要等待某些條件滿足而主動讓出CPU才能被考慮執行,這很明顯嚴重影響搶佔延遲。

在Linux 2.6中,內核已經可以搶佔,因而實時性得到了加強。但是內核中仍有大量的不可搶佔區域, 如由自旋鎖 (spinlock)保護的臨界區,以及一些顯式使用preempt_disable失效搶佔的臨界區。

2.中斷關閉

Linux在一些同步操作中使用了中斷關閉指令,中斷關閉將增大中斷延遲,降低系統的實時性。

3.自旋鎖(spinlock)

自旋鎖是在可搶佔內核和SMP情況下對共享資源的一種同步機制,一般地一個任務對共享資源的訪問是非常短暫的,如果兩個任務競爭一個共享的資源時,沒有得到資源的任務將自旋以等待另一個任務使用完該共享資源。這種鎖機制是非常高效的,但是在保持自旋鎖期間將失效搶佔,這意味着搶佔延遲將增加。在2.6內核中,自旋鎖的使用非常普遍,有的甚至對整個一個數組或鏈表的便歷過程都使用自旋鎖。因此搶佔延遲非常不確定。

4.大內核鎖

由於歷史原因,內核一直保留有幾個大內核鎖,大內核鎖實質上也是一種自旋鎖,但是它與一般的自旋鎖的區別是,它是用於同步整個內核的,而且一般該鎖的保持時間較長,也即搶佔失效時間長,因此它的使用將嚴重地影響搶佔延遲。

5.中斷總是最高優先級的

在Linux中,中斷(包括軟中斷)是最高優先級的,不論在任何時刻,只要產生中斷事件,內核將立即執行相應的中斷處理函數以及軟中斷,等到所有掛起的中斷和軟中斷處理完畢有才執行正常的任務。因此在標準的Linux系統上,實時任務根本不可能得到實時性保證。例如,假設在一個標準Linux系統上運行了一個實時任務(即使用了SCHED_FIFO調度策略並且設定了最高的實時優先級),但是該系統有非常繁重的網絡負載和I/O負載,那麼系統可能一直處在中斷處理狀態而沒有機會運行任何任務,這樣實時任務將永遠無法運行,搶佔延遲將是無窮大。因此,如果這種機制不改,實時Linux將永遠無法實現。

6.調度算法和調度點

在Linux 2.4和以前的版本,調度器的時間複雜度是O(n)的,而且在SMP的情況下性能低,因爲所有的CPU共享一個任務鏈表,任何時刻只能有一個調度器運行。因此,搶佔延遲很大程度上以來於當前系統的任務數,具有非常大的不確定性和不可預測性。

在2.6內核中引入的O(1)調度器很好地解決了這些問題。

此外,即使內核是可搶佔的,也不是在任何地方可以發生調度,例如在中斷上下文,一箇中斷處理函數可能喚醒了某一高優先級進程,但是該進程並不能立即運行,因爲在中斷上下文不能發生調度,中斷處理完了之後內核還要執行掛起的軟中斷,等它們處理完之後纔有機會調度剛纔喚醒的進程。在標準Linux內核中,調度點(有意安排的執行任務調度的點)並不多,對2.4和2.6內核測試的結果表明,缺乏調度點是影響Linux實時性的一個因素。

六、現存的Linux實時技術

現有的著名的實時Linux實現包括RTLinux、RTAI和TimeSys。

1. RTLinux

RTLinux是著名的研究機構FSMLab研發的一款實時Linux,既有GPL和Free版本,又有商業版本。它使用的實現方式是子內核方法,即把Linux內核作爲一個新實現的子內核的閒暇任務,子內核位於Linux內核和硬件抽象層之間,實時任務運行於子內核之上,只有當沒有實時任務需要運行時,Linux內核纔有機會運行。

特別是對中斷的管理,它採用了一種軟件的方式來處理Linux內的中斷關閉,當Linux內核關閉中斷後,並不是真正地屏蔽了硬件中斷,相反,它使用了一個變量來保存Linux內核的中斷標誌位,Linux內核的開關中斷只是影響了該變量,硬件的中斷由子內核來接管,當Linux內核關閉了中斷,子內核仍然可以響應任何中斷,只是如果子內核不需要處理的中斷才交給Linux內核來處理,如果Linux內核關閉了中斷,子內核將記錄該中斷並在Linux內核打開中斷後提交它處理。

在RTLinux裏,每一個實時任務都是內核線程,運行在內核空間,RTLinux提供了一套專門的機制來在實時任務和普通的Linux任務之間進行進程間通信。

這種子內核的實現提供了非常好的實時性,完全是一個硬實時的Linux。

2.TimeSys Linux

Timesys很早就發佈了實時Linux的商業版以及GPL版,它採用了與RTLinux完全不同的實現方式。前面已經提到了標準Linux內核的實時限制,TimeSys Linux就是通過消除這些限制來達到實時性的。它把中斷(IRQ)和軟中斷(softIRQ)全部線程化並賦予不同的優先級,實時任務可以有比中斷線程更高的優先級,它使用Mutex替代spinlock來使得自旋鎖完全可搶佔。它也對調度器做了優化使它是O(1)的(注:因爲使用2.4內核)。由於中斷已經線程化了,很多中斷關閉就沒必要了,因而消除了很多中斷關閉區域。它還實現了對CPU和網絡資源的預定來改善實時性。後面將說的Ingo's RT patch就是借鑑這些思路來實現實時性的。

這種實現方式保持了全部的Linux應用編程模式,實時應用和普通的應用採用同樣的編程方式,使用同樣的API,只是實時任務需要明確指定自己的優先級與調度策略。但是這種實現方式也有弊病,那就是它滿足硬實時性有一定的困難,因爲即使中斷關閉和不可搶佔區大爲減少,但是還是存在,一些中斷還是無法線程化,如時鐘中斷等。

3. Ingo's RT patch

Ingo's RT patch是又一個Linux實時實現,它採用了與TimeSys完全相同的技術路線,而且有一些實現是基於TimeSys的源代碼的,如IRQ和softirq線程化。但是它與前面提到的兩個實時實現不同的地方是,它可能併入到標準Linux內核(作者預見,可能併入到2.6.13或以後的某個版本中)。在最新的標準內核Linux 2.6.11中,已經出現了這個補丁曾經包含的部分代碼,如IRQ子系統,那是IRQ和softirq線程化的基礎,已經隱含了一些線程化的代碼,如自願搶佔代碼,那是2.4的低延遲補丁(low latency patch)和Ingo的一些自願搶佔代碼以及Robert Love的鎖分解補丁的集合,還有可搶佔的大內核鎖。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章