Linux进程冻结

Linux进程冻结

主要参考:

Documentation\power\freezing-of-tasks.rst

Freezing of tasks — The Linux Kernel documentation

【原创】Linux Suspend流程分析 - LoyenWang - 博客园 (cnblogs.com)

冻结任务

什么是任务冻结

这里的任务是指用户进程和部分内核线程。任务冻结是一种机制,在休眠或系统挂起(在某些体系结构上)期间,通过该机制可以控制用户空间进程和某些内核线程。

任务冻结的工作原理

每个任务有三个标志 PF_NOFREEZE,PF_FROZEN 和 PF_FREEZER_SKIP(最后一个是辅助标志)。 未设置 PF_NOFREEZE 的任务(所有用户空间进程和某些内核线程)被视为“可冻结的”,并在系统进入挂起状态之前以及在创建休眠映像之前以特殊方式进行处理(在此之后,我们仅考虑休眠,但说明也适用于暂停)。

系统范围的变量 system_freezing_cnt(与每个任务的标志相反)用于指示系统是否在进行冻结操作。然后 freeze_processes()设置此变量。此后,它将执行try_to_freeze_tasks(),该函数会向所有用户空间进程发送虚假信号(fake signal),并唤醒所有内核线程。所有可冻结的任务必须通过调用 try_to_freeze()来对此作出反应,会导致对 __refrigerator()(在kernel/freezer.c中定义)的调用,该调用会设置任务的 PF_FROZEN 标志,将任务状态更改为 TASK_UNINTERRUPTIBLE 并使其循环直到 PF_FROZEN 标志位被清除。然后,我们说任务是被“冻结的”,因此处理此机制的函数集称为“冻结器”(这些函数在kernel/power/process.c,

kernel/freezer.c & include/linux/freezer.h中定义。)。

注: 用户空间进程通常在内核线程之前冻结。

这是Loyen博客中的图片,比较详细列出了freze process过程.

用户进程冻结流程

先把一个全局变量pm_freezing设置为true

给每个进程都发送一个伪信号,也就是把所有进程都唤醒。

进程唤醒之后会运行,在其即将返回用户空间时会进行信号处理.

在信号处理的流程中,会先进行冻结检测后冻结.

先检测pm_freezing为true而且当前进程也不是免冻进程,就满足冻结的条件.

冻结该进程。冻结就是把进程的运行状态设置为不可运行,然后调度其它进程。

fake_signal_wake_up() 函数巧妙的利用了信号处理机制,只设置任务的 TIF_SIGPENDING 位,但不传递任何信号,然后唤醒任务;这样任务在返回用户态

时会进入信号处理流程,检查系统的freeze状态,并做相应处理。

内核线程冻结流程

内核线程的freeze必须主动调用函数触发。可以冻结的内核线程需要保证在合适的位置显示调用来freeze,可用接口有

try_to_freeze()

wait_event_freezable()

wait_event_freesable_timeout()

注: 如果可冻结的内核线程在冻结程序启动冻结操作后未能调用try_to_freeze(),任务冻结将失败,整个休眠操作将被取消。因此,可冻结内核线程必须在某处调用try_to_freeze()或使用wait_event_freezable()和wait_event_freesable_timeout()宏之一。

解冻任务

任务冻结和解冻API

freeze_processes():

/* -仅冻结用户空间任务 */

freeze_kernel_threads():

/* -冻结所有任务(包括内核线程),因为如果不冻结用户空间任务就无法冻结内核线程 */

thaw_kernel_threads():

/* -仅解冻内核线程; 如果我们需要在解冻内核线程和解冻用户空间任务之间做任何特殊的事情,或者如果我们想推迟解冻用户空间任务,这将特别有用。*/

thaw_processes():

/* -解冻所有任务(包括内核线程),因为我们必须解冻内核线程才能解冻用户空间任务 */

任务解冻的原理

从休眠映像还原系统内存状态并重新初始化设备后,将调用函数 thaw_processes() 以便为每个冻结的任务清除 PF_FROZEN 标志。 然后,已冻结的任务退出 __refrigerator()并继续运行

默认情况下,内核线程不可冻结。 但是,内核线程可以通过调用 set_freezable() 自行清除 PF_NOFREEZE(不允许直接重置PF_NOFREEZE)。 从这一点来看,它被视为可冻结的,必须在适当的位置调用 try_to_freezee()。

为什么需要任务冻结

1.主要原因是为了防止文件系统在休眠后损坏

2.要创建休眠映像,我们需要释放足够的内存(大约50%的可用RAM)

3.第三个原因是为了防止用户空间进程和某些内核线程干扰设备的挂起和恢复.

4.冻结任务的另一个原因是防止用户空间进程意识到发生了休眠(或挂起)操作。

注意事项

不鼓励持有 'system_transition_mutex' 锁来从系统范围的睡眠中互斥一段代码,例如暂停/休眠。 如果可能的话,那段代码必须改为挂接到挂起/休眠通知程序上,以实现互斥。 请查看CPU热插拔代码(kernel/cpu.c)作为示例.

[un]lock_system_sleep() API是安全的,因为它们要求冷冻器跳过冻结此任务,因为无论如何它已经“冻结”了,因为它已在 “system_transition_mutex”上被阻塞住了, 此锁仅在完成整个挂起/休眠流程之后才释放。 因此,总而言之,请使用 [un]lock_system_sleep() 而不是直接使用互斥锁 mutex_[un]lock(&system_transition_mutex)。 这样可以防止冻结失败.

相关推荐

微信被投诉赌博怎么办(微信赌博投诉)
365买球平台下载苹果

微信被投诉赌博怎么办(微信赌博投诉)

📅 08-25 👁️ 7969
王者荣耀成就怎么刷 王者荣耀成就等级怎么升
beat365手机下载

王者荣耀成就怎么刷 王者荣耀成就等级怎么升

📅 08-12 👁️ 8096
世界杯球迷全球区域分布图揭示不同国家热爱足球的热度差异
预售和现付的博弈:付定金和尾款为什么不能在同一天?
中国史上第一巨贪和珅的资产到底有多少?可以说是富可敌国!
qq克隆好友,轻松转移,手机克隆好友攻略,一键同步至新手机