Linux 的 冻结进程技术就是对signal 的一种封装 !
bool freeze_task(struct task_struct *p)
{
/*
≈≈100% 都是开关中断准备.
整个 freeze 都是在 disable irq 状态下进行的.
怕 Interrupt 来搅局呀. 整个 Linux kernel 无处不在的是防Interrupt
*/
unsigned long flags;
/*
用户空间进程默认是可以freeze的,
比如 你fork()
--> do_fork()
--> copy_process()
--> wake_up_process() .... 一个进程,
该 flags 默认值是根本就是没有置PF_FREEZER_SKIP这个位.
return p->flags & PF_FREEZER_SKIP;
但是如果你想随意的让一个Task freeze,那么是很困难的,
因为如果系统不开始进入freeze,Kernel 根本就不允许你让一个Task 休眠,kernel 严密性可见一斑 !!
OK ! 那么下面让 一个 用户APP freeze,看Linux Kernel 实现的多么的优秀!
这里典型的是 Kernel社区 向 辣鸡 Android 妥协了 ... N M !
看下面吧.
*/
if (freezer_should_skip(p))
return false;
/*
但使龙城飞将在,不叫胡马度长城 . 😄
*/
spin_lock_irqsave(&freezer_lock, flags);
/*
一 : frozen()
看这个task 是否已经被freeze过了, 这个是理所当然的.
static inline bool frozen(struct task_struct *p)
return p->flags & PF_FROZEN;
二 : freezing()
看这个system_freezing_cnt: 有效冻结的次数, 默认值是 0
system_freezing_cnt > 0 时, 表示系统要开始冻结了
好,那么它在什么时机会由默认值 + 1 呢 ?
这个函数freeze_processes() : 通知用户空间进程进入冻结了
所以 :
这里使用了 likely() 是十分有意义的的 !
if (likely(!atomic_read(&system_freezing_cnt)))
return false;
该函数底层调用 freezing_slow_path()函数,该函数里面有 4 个 if 来判断,
总之一句话 : 就是判断是否可以开始 冻结Task 了,
*/
if (!freezing(p) || frozen(p)) {
spin_unlock_irqrestore(&freezer_lock, flags);
return false;
}
spin_unlock_irqrestore(&freezer_lock, flags);
/*
以上都是判断, 真正的处理是在下面.
*/
/*
下面对用户空间线程 和 内核空间线程 做了分别的处理.
fork()
......
-----> copy_thread_tls()
好, 到这里冻结的设置操作就结束了. 他不做真实的冻结操作.
等待着signal的处理吧.
*/
if (!(p->flags & PF_KTHREAD))
fake_signal_wake_up(p);
else
wake_up_state(p, TASK_INTERRUPTIBLE);
spin_unlock_irqrestore(&freezer_lock, flags);
return true;
}