分享Linux程式凍結技術

安全劍客發表於2020-10-20
程式凍結技術(freezing of tasks)是指在系統hibernate或者suspend的時候,將使用者程式和部分核心執行緒置於“可控”的暫停狀態。

分享Linux程式凍結技術分享Linux程式凍結技術

1 什麼是程式凍結

程式凍結技術(freezing of tasks)是指在系統hibernate或者suspend的時候,將使用者程式和部分核心執行緒置於“可控”的暫停狀態。

2 為什麼需要凍結技術

假設沒有凍結技術,程式可以在任意可排程的點暫停,而且直到cpu_down才會暫停並遷移。這會給系統帶來很多問題:

(1)有可能破壞檔案系統。在系統建立hibernate image到cpu down之間,如果有程式還在修改檔案系統的內容,這將會導致系統恢復之後無法完全恢復檔案系統;

(2)有可能導致建立hibernation image失敗。建立hibernation image需要足夠的記憶體空間,但是在這期間如果還有程式在申請記憶體,就可能導致建立失敗;

(3)有可能干擾裝置的suspend和resume。在cpu down之前,device suspend期間,如果程式還在訪問裝置,尤其是訪問競爭資源,就有可能引起裝置suspend異常;

(4)有可能導致程式感知系統休眠。系統休眠的理想狀態是所有任務對休眠過程無感知,睡醒之後全部自動恢復工作,但是有些程式,比如某個程式需要所有cpu online才能正常工作,如果程式不凍結,那麼在休眠過程中將會工作異常。

3 程式碼實現框架

凍結的物件是核心中可以被排程執行的實體,包括使用者程式、核心執行緒和work_queue。使用者程式預設是可以被凍結的,借用訊號處理機制實現;核心執行緒和work_queue預設是不能被凍結的,少數核心執行緒和work_queue在建立時指定了freezable標誌,這些任務需要對freeze狀態進行判斷,當系統進入freezing時,主動暫停執行。

kernel threads可以透過呼叫kthread_freezable_should_stop來判斷freezing狀態,並主動呼叫__refrigerator進入凍結;work_queue透過判斷max_active屬性,如果max_active=0,則不能入隊新的work,所有work延後執行。

標記系統freeze狀態的有三個重要的全域性變數:pm_freezing、system_freezing_cnt和pm_nosig_freezing,如果全為0,表示系統未進入凍結;system_freezing_cnt》0表示系統進入凍結,pm_freezing=true表示凍結使用者程式,pm_nosig_freezing=true表示凍結核心執行緒和workqueue。它們會在freeze_processes和freeze_kernel_threads中置位,在thaw_processes和thaw_kernel_threads中清零。

fake_signal_wake_up函式巧妙的利用了訊號處理機制,只設定任務的TIF_SIGPENDING位,但不傳遞任何訊號,然後喚醒任務;這樣任務在返回使用者態時會進入訊號處理流程,檢查系統的freeze狀態,並做相應處理。

任務主動呼叫try_to_freeze的程式碼如下:

static inline bool try_to_freeze_unsafe(void)
{
if (likely(!freezing(current))) //檢查系統是否處於freezing狀態
return false;
return __refrigerator(false); //主動進入凍結
}
static inline bool freezing(struct task_struct *p)
{
if (likely(!atomic_read(&system_freezing_cnt))) //系統總體進入freezing
return false;
return freezing_slow_path(p);
}
bool freezing_slow_path(struct task_struct *p)
{
if (p-》flags & PF_NOFREEZE) //當前程式是否允許凍結
return false;
if (pm_nosig_freezing || cgroup_freezing(p)) //系統凍結kernel threads
return true;
if (pm_freezing && !(p-》flags & PF_KTHREAD)) //系統凍結使用者程式
return true;
return false;
}
進入凍結狀態直到恢復的主要函式:bool __refrigerator(bool check_kthr_stop)
{
。..
for (;;) {
set_current_state(TASK_UNINTERRUPTIBLE); //設定程式為UNINTERRUPTIBLE狀態
spin_lock_irq(&freezer_lock);
current-》flags |= PF_FROZEN; //設定已凍結狀態
if (!freezing(current) ||
(check_kthr_stop && kthread_should_stop())) //判斷系統是否還處於凍結
current-》flags &= ~PF_FROZEN; //如果系統已解凍,則取消凍結狀態
spin_unlock_irq(&freezer_lock);
if (!(current-》flags & PF_FROZEN)) //如果已取消凍結,跳出迴圈,恢復執行
break;
was_frozen = true;
schedule();
}
。..。..
}

原文地址:

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31559985/viewspace-2728042/,如需轉載,請註明出處,否則將追究法律責任。

相關文章