版權宣告:本文為本文為博主原創文章,轉載請註明出處 https://www.cnblogs.com/wsg1100。如有錯誤,歡迎指正。
- 一、前言
- PREEMPT-RT(RT Throttling)
- 一、xenomai watchdog介紹
- 二、xenomai watchdog工作原理
- 三、使用場景
本文介紹xenomai watchdog,有什麼用?它是如何工作的?
一、前言
介紹xenomai watchdog之前,有必要先介紹作業系統對實時任務的排程,實時任務的排程是指在滿足實時任務時間約束的情況下,對任務進行排隊和執行的策略。兩種常見的實時任務排程演算法是RR排程(Round Robin,輪轉排程)和FIFO排程(First In First Out,先進先出排程)。
正常情況下,高優先順序實時任務對CPU時間絕對的優先權。如果此時最高優先順序任務存在bug,出錯或進入一個不存在主動和被動讓出CPU資源的邏輯時,系統中的滑鼠、鍵盤、螢幕等非實時任務將會因為得不到CPU執行時間餓死,導致系統失去響應。
為此PREEMPT-RT和xenomai給出了不同的解決方案。
PREEMPT-RT(RT Throttling)
對於PREEMPT-RT,PREEMPT-RT提供了一個機制,確保非實時任務能在某個時間點執行,該機制也被稱為RT限流(RT Throttling),它由兩個值決定:
-
/proc/sys/kernel/sched_rt_period_us
定義了微秒級別的視窗,在這個視窗裡排程器會在實時和非實時任務之間共享資源,預設1 s。 -
/proc/sys/kernel/sched_rt_runtime_us
則規定了在上述視窗中為實時任務分配的時長比例。預設值950000us,即95%。意味著實時任務在每 1 秒內最多可以使用 950 毫秒的 CPU 時間,剩餘的 50 毫秒留給其他非實時任務。
可以透過以下方式修改這些值:
echo 950000 > /proc/sys/kernel/sched_rt_runtime_us
echo 1000000 > /proc/sys/kernel/sched_rt_period_us
需要注意的是,修改這些值需要超級使用者(root)許可權。
RT Throttling保證了即使實時任務出現錯誤或者無限迴圈,也會為非實時任務預留一定的CPU執行時間,方便我們定位和debug。
xenomai也有實時任務的限制措施xenomai watchdog,但與PREEMPT-RT的RT Throttling不同。
一、xenomai watchdog介紹
xenomai watchdog是xenomai核心提供的一個檢測xenomai實時任務是否長期佔用CPU機制,核心編譯時透過以下配置啟用該功能。
[*] Xenomai/cobalt --->
[*] Debug support --->
[*] Watchdog support
(4) Watchdog timeout
其中Watchdog timeout
是看門狗動作的超時時間,時間單位是秒,允許配置的預設最大時間為60秒。核心啟用後,看門狗超時時間還可透過核心引數watchdog_timeout
在啟動時修改,單位:秒,值不受限制。
當xenomai watchdog觸發時,watchdog會向當前cpu執行的執行緒傳送SIGDEBUG signal,該訊號會使實時任務結束,同時核心會輸出資訊,實時任務結束後系統恢復響應,透過demsg
命令可以看到。
[Xenomai] watchdog triggered on CPU #0 -- runaway thread 'RT_Thread' signaled
那xenomai watchdog是如何工作的?有什麼侷限?不使用會發生什麼?
二、xenomai watchdog工作原理
我們知道Xenomai 是一個雙排程核作業系統,它在核心態新增了一個高優先順序的實時排程核 Cobalt 來管理實時任務。Cobalt 排程核與 Linux 排程核共存,透過 Ipipeline 機制將兩個排程上下文分為實時域和非實時域,Ipipeline 確保了 Cobalt 核心(實時域)的優先順序高於 Linux 核心(非實時域,也稱root domain),linux核心退化為成為 Cobalt 核心的idle任務,從而保障實時任務的實時性;(有關該部分,請查閱本部落格其他文章)。
實時域和非實時域會隨著任務的執行情況而來回切換。當沒有實時任務需要執行釋放CPU資源給linux非實時任務,或者實時任務呼叫了linux提供的系統資源的實時,會切換到非實時域。
看門狗的觸發邏輯是這樣的,當進入實時任務排程上下文的時候,看門狗啟動開始定時,離開實時上下文(實時任務呼叫了非實時服務或者主動睡眠讓出 cpu) 停止,只要看門狗超時說明實時任務在這段時間內一直在執行,看門狗看管的是整個實時任務集合,不是某個特定任務,看門狗超時觸發的時候會把當前 cpu 執行的任務 kill 掉,任何一個實時任務都有可能在watchdog觸發這個時間點上。
具體程式碼如下:
static inline void enter_root(struct xnthread *root)
{
struct xnarchtcb *rootcb __maybe_unused = xnthread_archtcb(root);
#ifdef CONFIG_XENO_OPT_WATCHDOG
xntimer_stop(&root->sched->wdtimer);
#endif
/*...*/
}
static inline void leave_root(struct xnthread *root)
{
struct xnarchtcb *rootcb = xnthread_archtcb(root);
struct task_struct *p = current;
/*...*/
#ifdef CONFIG_XENO_OPT_WATCHDOG
xntimer_start(&root->sched->wdtimer, get_watchdog_timeout(),
XN_INFINITE, XN_RELATIVE);
#endif
}
而看門狗處理邏輯也很簡單,如果當前處於是root域,不處理;若當前是使用者態實時任務,則直接傳送訊號;若當前執行的核心態實時任務,則將當前任務狀態設定為XNKICKED並取消執行。
static void watchdog_handler(struct xntimer *timer)
{
struct xnsched *sched = xnsched_current();
struct xnthread *curr = sched->curr;
if (likely(xnthread_test_state(curr, XNROOT))) {/*當前處於root域*/
xnsched_reset_watchdog(sched);
return;
}
if (likely(++sched->wdcount < wd_timeout_arg))
return;
trace_cobalt_watchdog_signal(curr);
if (xnthread_test_state(curr, XNUSER)) { /*使用者態實時任務*/
printk(XENO_WARNING "watchdog triggered on CPU #%d -- runaway thread "
"'%s' signaled\n", xnsched_cpu(sched), curr->name);
xnthread_call_mayday(curr, SIGDEBUG_WATCHDOG);
} else { /*核心態實時任務*/
printk(XENO_WARNING "watchdog triggered on CPU #%d -- runaway thread "
"'%s' canceled\n", xnsched_cpu(sched), curr->name);
/*
* On behalf on an IRQ handler, xnthread_cancel()
* would go half way cancelling the preempted
* thread. Therefore we manually raise XNKICKED to
* cause the next call to xnthread_suspend() to return
* early in XNBREAK condition, and XNCANCELD so that
* @thread exits next time it invokes
* xnthread_test_cancel().
*/
xnthread_set_info(curr, XNKICKED|XNCANCELD);
}
xnsched_reset_watchdog(sched);
}
三、使用場景
xenomai watchdog會導致出問題的實時任務退出,所以一般在實時軟體開發階段,開啟watchdog可以儘早暴露實時應用潛在的出錯或無限迴圈問題,避免軟體釋出後產生嚴重後果。
如果實時應用釋出後,在特定場景下出現系統無響應問題,可用啟用watchdog來排查定位。
下一篇文章,我將給大家介紹一個真實生產環境中遇到的問題,一個外部條件觸發低優先順序實時任務進入無限迴圈邏輯後,導致整個系統實時任務排程異常的問題,敬請期待。