日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux实时进程优先级rt,Linux实时性- PREEMPT_RT实时抢占实现

發(fā)布時間:2023/12/4 linux 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux实时进程优先级rt,Linux实时性- PREEMPT_RT实时抢占实现 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

作者:Paul E. McKenney

翻譯整理:土豆絲624

原文鏈接:

概述:

本篇文章主要講Linux的實時包PREEMPT_RT 是如何實現(xiàn)的。

PREEMPT_RT 的原理

PREEMPT_RT包的關(guān)鍵點是要使非搶占式的內(nèi)核代碼量盡可能的少,同時為了提供搶占性而必須修改的代碼量也要盡可能的少。特別是臨界區(qū),中斷處理程序和中斷禁用的代碼序列通常是可搶占式的。PREEMPT_RT包充分利用Linux內(nèi)核的SMP能力來增加額外的搶占能力,而不是重寫Linux內(nèi)核。某種程度上,可以認(rèn)為是搶占是給系統(tǒng)新加了一個CPU,然后使用常規(guī)鎖定原語與搶占任務(wù)采取的任何操作進(jìn)行同步。

注意:這里說的一些原理不要從字面意思上去理解。比如PREEMPT_RT包對每個搶占并不是一個熱拔插事件。關(guān)鍵點是使用搶占必須提供SMP機制。后面的章節(jié)會詳細(xì)介紹如何應(yīng)用這些原理。

PREEMPT_RT的功能

PREEMPT_RT包有如下特性

搶占式臨界區(qū)

搶占式中斷處理

搶占式中斷禁止代碼序列

內(nèi)核自旋鎖和信號量的優(yōu)先級繼承

遞延操作

降低延遲的措施

搶占式臨界區(qū)

在PREEMPT_RT中,普通的自旋鎖(spinlock_t and rwlock_t)是搶占式的,RCU讀取側(cè)臨界區(qū)((rcu_read_lock() 和rcu_read_unlock())也是一樣的。信號量臨界區(qū)是可搶占的,他們已經(jīng)存在于可搶占和非搶占內(nèi)核中。這種可搶占性意思是可以阻止獲取自旋鎖,也就是在可搶占或中斷禁用的情況下獲取自旋鎖是非法的(這個原則的一個例外就是變體_trylock,只要不是在密集信號中重復(fù)調(diào)用)。這也意味著當(dāng)使用spinlock_t的時候spin_lock_irqsave()不會禁用硬件中斷。

問題1:如何在非搶占內(nèi)核中實現(xiàn)搶占式信號量臨界區(qū)?

在中斷或搶占禁用的情況下要獲取鎖要做什么?用raw_spinlock_t而不是spinlock_t,調(diào)用spin_lock()的時候使用raw_spinlock_t。PREEMPT_RT包含一個宏集合,這樣會讓spin_lock()調(diào)用的時候就像c++中的函數(shù)重載。當(dāng)使用raw_spinlock_t的時候,就是傳統(tǒng)的自旋鎖。但是當(dāng)使用spinlock_t,臨界區(qū)就是可搶占的。當(dāng)使用raw_spinlock_t時,各種_irq原語(例如spin_lock_irqsave())會禁用硬件中斷,而在使用spinlock_t時不會禁用硬件中斷。但是,使用raw_spinlock_t(及其對應(yīng)的rwlock_t,raw_rwlock_t)應(yīng)該是例外,而不是常規(guī)使用。在一些底層區(qū)域比如調(diào)度,特定的架構(gòu)代碼和RCU,是不需要這些原始鎖的。

自從臨界區(qū)可以被搶占,就不能依賴單個CPU上給定的臨界區(qū)。因為是可搶占的,所以可能會移到其他的CPU上。所以,當(dāng)你在臨界區(qū)使用per-CPU變量時,必須單獨處理搶占的可能性。因為spinlock_t和rwlock_t不再具有這個功能。

可以通過以下兩種方式實現(xiàn)。

1. 顯示禁用中斷,或者通過調(diào)用get_cpu_var(), preempt_disable(),或者禁掉硬件中斷

2. 使用per-CPU鎖來保護(hù)per-CPU變量,可以通過使用新的DEFINE_PER_CPU_LOCKED()原語。

由于spin_lock可以睡眠,所以會增加一個額外的任務(wù)狀態(tài)。思考一下下面的代碼序列

spin_lock(&mylock1);

current->state = TASK_UNINTERRUPTIBLE;

spin_lock(&mylock2); // [*]

blah();

spin_unlock(&mylock2);

spin_unlock(&mylock1);

由于第二個spin_lock()調(diào)用可以睡眠,所以有可能會改變current-state的值,有可能使函數(shù)blah()產(chǎn)生令人驚訝的結(jié)果。在這種情況下,調(diào)度程序可以使用新的TASK_RUNNING_MUTEX位來保留current-state之前的值。盡管生成的環(huán)境有點陌生,但是通過少量的代碼改動就實現(xiàn)了臨界區(qū)搶占,并且PREEMPT_RT, PREEMPT和 non-PREEMPT三個配置項都是用相同的代碼。

搶占式中斷處理

在Preempt_RT環(huán)境中幾乎所有的進(jìn)程上下文都有中斷處理。雖然任何標(biāo)為SA_NODELAY的中斷都可以在其上下文中運行,但是僅在fpu_irq, irq0, irq2和lpptest指定了SA_NODELAY。其中,只有irq0(per-CPU計時器中斷)可以正常使用。fpu-irq是用于浮點協(xié)處理器中斷,而lpptest是用于中斷等待時間基準(zhǔn)測試。注意軟件計時器(add_timer())不在硬件上下文中運行。它是運行在進(jìn)程上下文中,并且是完全搶占式的。

注意不要輕易使用SA_NODELAY,因為它會大大降低中斷和調(diào)度延遲。Per-CPU計時器中斷之所以符合條件,是因為它與調(diào)度程序和其他核心內(nèi)核組件緊密相關(guān)。此外,在寫SA_NODELAY中斷處理代碼的時候必須要非常謹(jǐn)慎,否則很容易出現(xiàn)崩潰和死鎖。

由于per-CPU計時器中斷運行在硬件中斷上下文中,因此任何和進(jìn)程上下文代碼共享的鎖必須是原始自旋鎖(raw_spinlock_t 或 raw_rwlock_t)。并且,從進(jìn)程上下文獲取時,必須使用_irq變體,比如spin_lock_irqsave()。另外,當(dāng)進(jìn)程上下文代碼訪問每個和SA_NODELAY中斷處理程序共享的per-CPU變量的時候,一般上要禁用硬件中斷。

搶占式“中斷禁用”代碼序列

搶占式中斷禁用代碼序列的概念從術(shù)語上理解似乎是矛盾的,但是牢記PREEMPT_RT原理很重要。原理就是要依靠Linux內(nèi)核的SMP功能來處理和中斷處理程序的競爭。大多數(shù)中斷處理程序都運行在進(jìn)程上下文中。任何與中斷處理程序有交互的代碼都要準(zhǔn)備處理在其他CPU上同時運行的該中斷處理程序。

因此,spin_lock_irqsave()和相關(guān)的原語不需要禁用搶占。之所以安全的原因是,即使中斷處理程序運行,即使它搶占了擁有spinlock_t的代碼,但是在試圖獲取spinlock_t的時候會立即阻塞。臨界區(qū)依舊會被保留。

但是,local_irq_save()依舊禁用搶占,因為沒有任何鎖依賴它。因此使用鎖而不是local_irq_save()可以降低調(diào)度延遲,但是以這種方式替換鎖會降低SMP性能,因此要小心。

需要和SA_NODELAY中斷交互的代碼不能使用local_irq_save(),因為它沒用禁用硬件中斷。相反,應(yīng)該使用raw_local_irq_save(),類似的,當(dāng)需要和SA_NODELAY中斷處理程序交互的時候,需要使用原始自旋鎖(raw_spinlock_t, raw_rwlock_t 和raw_seqlock_t)。但是原始自旋鎖和原始中斷禁用不應(yīng)該在一些底層區(qū)域,如調(diào)度程序,架構(gòu)依賴代碼和RCU之外使用。

內(nèi)核自旋鎖和信號量的優(yōu)先級繼承

實時程序員會經(jīng)常擔(dān)心優(yōu)先級倒置,這可能會發(fā)生一下幾種情況:

低優(yōu)先級任務(wù)A獲取資源,比如獲取鎖

中優(yōu)先級任務(wù)B開始執(zhí)行CPU綁定,搶占低優(yōu)先級任務(wù)A

高優(yōu)先級任務(wù)C試圖獲取低優(yōu)先任務(wù)A持有的鎖,但是被阻塞了。因為中優(yōu)先級任務(wù)B已經(jīng)搶占了低優(yōu)先級任務(wù)A

這種優(yōu)先級倒置可以無限期地延遲高優(yōu)先級任務(wù)。有兩種方式可以解決這個問題:(1)抑制搶占;(2)優(yōu)先級繼承。第一種情況,由于沒有搶占,所以任務(wù)B不能搶占任務(wù)A,從而阻止優(yōu)先級反轉(zhuǎn)的發(fā)生。這種方式在PREEMPT內(nèi)核中用于自旋鎖,但不用于信號量。抑制搶占對于信號量來說是沒有意義的。因為持有一個信號量的時候阻塞是合法的,即使沒有搶占也會導(dǎo)致優(yōu)先級反轉(zhuǎn)。對于某些實時工作負(fù)載,自旋鎖也不能抑制搶占,因為會對調(diào)度延遲造成影響。

優(yōu)先級繼承可以用在搶占抑制沒有意義的場合。就是高優(yōu)先級任務(wù)臨時把優(yōu)先級贈與持有關(guān)鍵鎖的低優(yōu)先級任務(wù)。優(yōu)先級繼承是可以傳遞的:在上面的例子中,如果更高優(yōu)先級任務(wù)D試圖獲取高優(yōu)先級任務(wù)C已經(jīng)持有的第二把鎖,任務(wù)C和A都將暫時提升為任務(wù)D的優(yōu)先級。優(yōu)先級提升的持續(xù)時間也受到嚴(yán)重限制:一旦低優(yōu)先級任務(wù)A釋放了鎖,它會立刻失去臨時提升的優(yōu)先級,把鎖交給任務(wù)C。

但是,任務(wù)C運行需要時間,很可能同時另一個更高優(yōu)先級任務(wù)E來試圖獲取鎖。如果發(fā)生這種情況,任務(wù)E會從任務(wù)C那里偷到鎖。這樣是合法的,因為任務(wù)C還沒有運行,因此實際上它并沒有獲取鎖。另一方面,如果任務(wù)C在任務(wù)E試圖獲取鎖之前已經(jīng)運行,那么任務(wù)E是無法偷鎖的,必須等待任務(wù)C釋放鎖,可能會提高任務(wù)C的優(yōu)先級以加快處理速度。

另外,在某些情況下會長時間保持鎖定。其中一些增加了“搶占點”,以便鎖持有者在某些其他任務(wù)需要時丟棄該鎖。

事實證明,讀寫優(yōu)先級繼承特別成問題。因此,盡管任務(wù)可以遞歸獲取,但Preempt_RT可以通過一次只允許一個任務(wù)獲取讀寫鎖或信號量來簡化這個為題。盡管限制了可擴展性,但這讓優(yōu)先級繼承實現(xiàn)成為可能。

問題2:實現(xiàn)讀寫優(yōu)先級繼承的簡單快捷的方法是什么

此外,在某些情況下,信號量不需要優(yōu)先級繼承,比如當(dāng)信號量用于事件機制而不是鎖的時候。compat_semaphore 和compat_rw_semaphore變體可以用于這種情況。很多信號量原語(up(), down()等)可用于compat_semaphore 和compat_rw_semaphore。相同的,讀寫信號量原語(up_read(), down_write()等)可用于compat_rw_semaphore 和rw_semaphore。

總結(jié)一下,優(yōu)先級繼承可以防止優(yōu)先級反轉(zhuǎn),允許高優(yōu)先級任務(wù)及時獲取鎖和信號量,即使這些鎖和信號量被低優(yōu)先級任務(wù)持有。PREEMPT_RT的優(yōu)先級繼承具有傳遞性且能夠及時移除,并且具有當(dāng)高優(yōu)先級任務(wù)突然需要低優(yōu)先任務(wù)持有的鎖時,處理這種情況的靈活性。當(dāng)信號量用于事件機制的時候,compat_semaphore 和compat_rw_semaphore可以避免優(yōu)先級繼承。

遞延操作

由于spin_lock()現(xiàn)在可以休眠,所以當(dāng)搶占或中斷被禁用的時候,調(diào)用它就不再合法了。在一些情況下,可以通過遞延操作要求spin_lock()等到搶占被重新啟用的時候來解決這個問題。

當(dāng)合法獲取task_struct中的spinlock_t alloc_lock是,可以將put_task_struct()放到put_task_struct_delayed()隊列中,以便延遲運行。

把mmdrop()放到mmdrop_delayed()隊列中,延遲運行。

TIF_NEED_RESCHED_DELAYED重新調(diào)度,不過需要等到進(jìn)程返回到用戶空間,或者等到下一個preempt_check_resched_delayed()。無論哪種方式,關(guān)鍵點在于避免在喚醒高優(yōu)先級任務(wù)直到當(dāng)前任務(wù)未鎖定之前無法取得進(jìn)展的情況下進(jìn)行不必要的搶占。沒有TIF_NEED_RESCHED_DELAYED,高優(yōu)先級任務(wù)會立刻搶占低優(yōu)先級任務(wù),只能被快速阻塞等待低優(yōu)先級任務(wù)持有的鎖。

解決方案是在spin_unlock()之后增加wake_up()去替代wake_up_process_sync()。如果喚醒的進(jìn)程搶占當(dāng)前進(jìn)程,通過TIF_NEED_RESCHED_DELAYED,喚醒操作會被延遲。

在所有這些情況下,解決方案是將操作推遲到可以更安全或更方便地執(zhí)行該操作。

降低延遲的操作

在PREEMPT_RT中的一些改變,主要目的是降低調(diào)度或中斷延遲。

第一種改變是引入x86 MMX/SSE硬件。這個硬件在內(nèi)核中處理中斷禁用。某些情況下意味著等待直到MMX/SSE指令完成。一些MMX/SSE指令沒有問題,但是有些指令要花很長時間,所以PREEMPT_RT拒絕使用這些很慢的指令。

第二個改變是使用per-CPU變量用于板坯分配器,以代替之前隨意的中斷禁用。

總結(jié)

以上是生活随笔為你收集整理的linux实时进程优先级rt,Linux实时性- PREEMPT_RT实时抢占实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。