Linux kernel在spinlock、irq上下文方面無法搶占,是以高優先級任務被喚醒到得以執行的時間并不能完全确定。同時,Linux kernel本身也不處理優先級反轉。RT-Preempt Patch是在Linux社群kernel的基礎上,加上相關的更新檔,以使得Linux滿足硬實時的需求。本文描述了該patch在PC上的實踐。我們的 測試環境為Ubuntu 10.10,預設情況下使用Ubuntu 10.10自帶的kernel:
在Ubuntu 10.10,apt-get install rt-tests安裝rt測試工具集,運作其中的cyclictest測試工具,預設建立5個SCHED_FIFO政策的realtime線程,優先級 76-80,運作周期是1000,1500,2000,2500,3000微秒:
由此可見在标準Linux内,rt線程投入運作的jitter非常不穩定,最小值在26-37微秒,平均值為68-889微秒,而最大值則分布在9481-13673微秒之間。
我們還是運作這個測試,但是在運作這個測試的過程中引入更多幹擾,如mount /dev/sdb1 ~/development,則結果變為:
mount過程中引入的irq、softirq和spinlock導緻最大jitter明顯地加大甚至達到了331482us,充分顯示出了标準Linux核心中RT線程投入運作時間的不可預期性(硬實時要求意味着可預期)。
如果我們編譯一份kernel,選擇的是“Voluntary Kernel Preemption (Desktop)“,這類似于2.4不支援kernel搶占的情況,我們運作同樣的case,時間的不确定性大地幾乎讓我們無法接受:
RT-Preempt Patch對Linux kernel的主要改造包括:
Making in-kernel locking-primitives (using spinlocks) preemptible though reimplementation with rtmutexes:
Critical sections protected by i.e. spinlock_t and rwlock_t are now preemptible. The creation of non-preemptible sections (in kernel) is still possible with raw_spinlock_t (same APIs like spinlock_t)
Converting interrupt handlers into preemptible kernel threads: The RT-Preempt patch treats soft interrupt handlers in kernel thread context, which is represented by a task_struct like a common userspace process. However it is also possible to register an IRQ in kernel context.
Converting the old Linux timer API into separate infrastructures for high resolution kernel timers plus one for timeouts, leading to userspace POSIX timers with high resolution.
在本試驗中,我們取的帶RT- Preempt Patch的kernel tree是git://git.kernel.org/pub/scm/linux/kernel/git/rt/linux-stable- rt.git,使用其v3.4-rt-rebase branch,編譯kernel時選中了"Fully Preemptible Kernel"搶占模型:
───────────────────────── Preemption Model ─────────────────────────┐
│ │ ( ) No Forced Preemption (Server)
│ │ ( ) Voluntary Kernel Preemption (Desktop)
│ │ ( ) Preemptible Kernel (Low-Latency Desktop)
│ │ ( ) Preemptible Kernel (Basic RT)
│ │ (X) Fully Preemptible Kernel (RT)
另外,kernel中需支援tickless和高精度timer:
┌───────────────────Processor type and features ─────────────────────────┐
│ │ [*] Tickless System (Dynamic Ticks)
│ │ [*] High Resolution Timer Support
make modules_install、make install、mkintramfs後,我們得到一個可以在Ubuntu中啟動的RT kernel。具體編譯方法可詳見http://www.linuxidc.com/Linux/2012-01/50749.htm,根據該文修改版本 号等資訊即可,我們運作的指令包括:
在grub.conf中增加新的啟動entry,仿照現有的menuentry,增加一個新的,把其中的相關版本号都變更為3.4.11-rt19,我們的修改如下:
開機時選擇3.4.11-rt19啟動:
運作同樣的測試cyclictest benchmark工具,結果迥異:
時間在可預期的範圍内,沒有出現标準kernel裡面jitter達到331482的情況。需要說明的是,這個jitter大到超過了我們的預期,達到了10ms量級,相信是受到了我們的測試都是在Virtualbox虛拟機進行的影響。按照其他文檔顯示,這個jitter應該在數十us左右。
我們在這個kernel裡面運作ps aux指令,可以看出線程化了的irq:
在其中編寫一個RT 線程的應用程式,通常需要如下步驟:
Setting a real time scheduling policy and priority.
Locking memory so that page faults caused by virtual memory will not undermine deterministic behavior
Pre-faulting the stack, so that a future stack fault will not undermine deterministic behavior
例 子test_rt.c,其中的mlockall是為了防止程序的虛拟位址空間對應的實體頁面被swap出去,而stack_prefault()則故意提 前導緻stack往下增長8KB,是以其後的函數調用和局部變量的使用将不再導緻棧增長(依賴于page fault和記憶體申請):
編譯之:gcc -o test_rt test_rt.c -lrt。本節就到這裡,後續我們會有一系列博文來描述RT-Preempt Patch對kernel的主要改動,以及其工作原理。
本文轉自 21cnbao 51CTO部落格,原文連結:http://blog.51cto.com/21cnbao/1011931,如需轉載請自行聯系原作者