在Linux中,休眠主要分三個主要的步驟:(1)凍結用戶態進程和內核態任務;(2)調用註冊的設備的suspend的回調函數;(3)按照註冊順序休眠核心設備和使CPU進入休眠態。
凍結進程是內核把進程列表中全部的進程的狀態都設置爲中止,而且保存下全部進程的上下文。當這些進程被解凍的時候,他們是不知道本身被凍結過的,只是簡單的繼續執行。如何讓Linux進入休眠呢?用戶能夠經過讀寫sys文件/sys /power/state 是實現控制系統進入休眠。好比:
# echo standby > /sys/power/state命令系統進入休眠。也可使用
# cat /sys/power/state來獲得內核支持哪幾種休眠方式。 linux
Linux Suspend 的流程。相關的文件的路徑:
linux_soruce/kernel/power/main.c
linux_source/kernel/arch/xxx/mach-xxx/pm.c 函數
linux_source/driver/base/power/main.c
(1)接下來讓咱們詳細的看一下Linux是怎麼休眠/喚醒的。 設計
用戶對於/sys/power/state 的讀寫會調用到 main.c中的state_store(),用戶能夠寫入 const char * const pm_state[] 中定義的字符串,好比"mem"、 "standby"。而後state_store()會調用enter_state(),它首先會檢查一些狀態參數,而後同步文件系統。
(2)準備凍結進程。 進程
當進入到suspend_prepare()中之後,它會給suspend分配一個虛擬終端來輸出信息,而後廣播一個系統要進入suspend的 Notify,關閉掉用戶態的helper進程,而後一次調用suspend_freeze_processes()凍結全部的進程,這裏會保存全部進程 當前的狀態,也許有一些進程會拒絕進入凍結狀態,當有這樣的進程存在的時候,會致使凍結失敗,此函數就會放棄凍結進程,而且解凍剛纔凍結的全部進程。 事件
(3)讓外設進入休眠。 字符串
如今,全部的進程(也包括workqueue/kthread) 都已經中止了,內核態任務有可能在中止的時候握有一些信號量,因此若是這時候在外設裏面去解鎖這個信號量有可能會發生死鎖,因此在外設的suspend()函數裏面做lock/unlock鎖要很是當心,這裏建議設計的時候就不要在suspend()裏面等待鎖。
最後會調用suspend_devices_and_enter()來把全部的外設休眠,在這個函數中,若是平臺註冊了suspend_pos(一般是在 板級定義中定義和註冊),這裏就會調用suspend_ops->begin(),而後driver/base/power/main.c 中的 device_suspend()->dpm_suspend() 會被調用,他們會依次調用驅動的suspend() 回調來休眠掉全部的設備。當全部的設備休眠之後,suspend_ops->prepare()會被調用,這個函數一般會做一些準備工做來讓板機進 入休眠。接下來Linux,在多核的CPU中的非啓動CPU會被關掉,經過註釋看到是避免這些其餘的CPU形成race condion,接下來的之後只有一個CPU在運行了。
suspend_ops 是板級的電源管理操做,一般註冊在文件 arch/xxx/mach-xxx/pm.c 中。接下來,suspend_enter()會被調用,這個函數會關閉arch irq,調用 device_power_down(),它會調用suspend_late()函數,這個函數是系統真正進入休眠最後調用的函數,一般會在這個函數中做最後的檢查。若是檢查沒問題,接下來休眠全部的系統設備和總線,而且調用 suspend_pos->enter() 來使CPU進入省電狀態。這時候,就已經休眠了,代碼的執行也就停在這裏了。 回調函數
(4)Resume。 同步
若是在休眠中系統被中斷或者其餘事件喚醒,接下來的代碼就會開始執行,這個喚醒的順序是和休眠的順序相反的,因此係統設備和總線會首先喚醒,使能系統中 斷,使能休眠時候中止掉的非啓動CPU,以及調用suspend_ops->finish(),並且在 suspend_devices_and_enter()函數中也會繼續喚醒每一個設備,使能虛擬終端。最後調用 suspend_ops->end()。再返回到enter_state()函數中的,當suspend_devices_and_enter() 返回之後,外設已經喚醒了,可是進程和任務都仍是凍結狀態,這裏會調用suspend_finish()來解凍這些進程和任務,並且發出Notify來表 示系統已經從suspend狀態退出,喚醒終端。到這裏,全部的休眠和喚醒就已經完畢了,系統繼續運行了。 io