Linux内核中kill_orphaned_pgrp函数是如何处理孤儿进程组的?
摘要:Linux 3.2 kill_orphaned_pgrp 函数 前言 之前研究进程的退出 do_exit, 其中一个重点就是 exit_notify, 遂对这个函数的用法产生了兴趣, 并且进行了一番研究. 1.想象一个场景 如果你玩过 sh
Linux 3.2 kill_orphaned_pgrp 函数
前言
之前研究进程的退出 do_exit, 其中一个重点就是 exit_notify, 遂对这个函数的用法产生了兴趣, 并且进行了一番研究.
1.想象一个场景
如果你玩过 shell, 你应该能理解下面的一个场景:
sudo-su-bash@Sudo-su-BashdeMacBook-Air ~ % sleep 100
^Z
zsh: suspended sleep 100
sudo-su-bash@Sudo-su-BashdeMacBook-Air ~ % nc -l 8080
^Z
zsh: suspended nc -l 8080
sudo-su-bash@Sudo-su-BashdeMacBook-Air ~ % jobs
[1] - suspended sleep 100
[2] + suspended nc -l 8080
sudo-su-bash@Sudo-su-BashdeMacBook-Air ~ % fg %1
[1] - continued sleep 100
^Z
zsh: suspended sleep 100
sudo-su-bash@Sudo-su-BashdeMacBook-Air ~ % bg %1
[1] - continued sleep 100
sudo-su-bash@Sudo-su-BashdeMacBook-Air ~ % exit
对, 按下 Ctrl+Z 可以让前台的进程暂时挂起, 然后使用 bg 可以让进程在后台运行.
但是随之而来的就有一个问题: 上面的代码, 我最后敲了 exit, shell挂了, 但是 sleep 和 nc 还挂在后台呢! 所以, 该怎么处置这两个怪胎? 接下来这个函数, 就是专门处置这个怪胎的.
2.函数的原型
这个函数的意图其实很简单, 看名字也可以看得出来, 就是检测是否为孤儿进程组, 并且唤醒/杀死孤儿进程组的所有 Stopped 状态的进程.
此函数的原型如下
static void
kill_orphaned_pgrp(struct task_struct *tsk, struct task_struct *parent)
{
struct pid *pgrp = task_pgrp(tsk);
struct task_struct *ignored_task = tsk;
if (!parent)
parent = tsk->real_parent;
else
ignored_task = NULL;
if (task_pgrp(parent) != pgrp &&
task_session(parent) == task_session(tsk) &&
will_become_orphaned_pgrp(pgrp, ignored_task) &&
has_stopped_jobs(pgrp)) {
__kill_pgrp_info(SIGHUP, SEND_SIG_PRIV, pgrp);
__kill_pgrp_info(SIGCONT, SEND_SIG_PRIV, pgrp);
}
}
初次看到, 肯定会感觉有点绕, 后面的代码勉强能看懂, 但是前面的代码是什么鬼?
为什么parent为null的时候, 会被自动赋值为父进程?
ignored_task又是干什么的?
3. 下面一段代码的含义
3.1 孤儿进程组的判定
在开始之前, 我们先来看一个函数:
//will_become_orphaned_pgrp
static int will_become_orphaned_pgrp(struct pid *pgrp, struct task_struct *ignored_task)
{
//确定每个进程的父进程都在同一个进程组
struct task_struct *p;
do_each_pid_task(pgrp, PIDTYPE_PGID, p) {
if ((p == ignored_task) || //被忽略的进程
(p->exit_state && thread_group_empty(p)) || //这个进程只剩下一个线程了, 并且这个线程也不在运行
is_global_init(p->real_parent)) //父进程全局init
continue;
if (task_pgrp(p->
