对于 Linux,如何使用系统调用终止一个会话(具有相同 SID)中的所有进程?

For Linux, how can I kill all processes in a session (with same SID) using system calls?

我想弄清楚如何使用 C 系统调用来杀死会话中的所有进程(具有相同的 SID)。我对只杀死具有特定 PGID 的所有进程不感兴趣,因为我对所有进程都不感兴趣about 没有相同的 PGID,但它们有相同的 SID。

我的研究只发现了这个,Graeme 对脚本做了一个很好的回答: https://unix.stackexchange.com/questions/124127/kill-all-descendant-processes

我很高兴得到关于如何杀死 所有 直系后代 children 的答案,更高兴我如何杀死所有 children 在会话中。

或者我问的可能吗?我对那里的解决方案不感兴趣,我只是列出 parents 后代的 PID。

您始终可以使用 /proc/ 文件系统来查询进程(请参阅 proc(5) for more). In particular you can then scan the /proc/PID/ directories (where PID is some numerical name like 1234, it is the relevant pid, so process of pid 1234 is described in /proc/1234/ pseudo-directory; hence you could readdir the /proc/ directory and find every numerical name inside it) and check which processes have a defined parent pid. You'll read sequentially pseudo-files like /proc/1234/status (and its PPid: line). See also this answer and that one

据我了解,您不能安全地这样做。 您可以安全终止的唯一进程是您的直接 children,因为只有对它们,您才能确定它们的 pid 是准确的。*

对于任何其他进程,它们的非children进程的pid是一个移动的目标(虽然移动非常非常缓慢,除非你在一个非常繁忙的系统上,进程疯狂地产生,使pid回收速度非常快)。

所以理论上你可以遍历进程树,例如:

#This will create a nice process tree
(sleep 1000 & ( sleep 1000&  sleep 1000& sleep 1000)&  sleep 1000 )&
#View it with 
ps T --forest
#Or recursively get all the nodes (this should match the corresponding part of the above ps command)
walk_processes() { echo ; cat /proc//task//children | while read -d ' ' pid; do walk_processes $pid; done;  }
walk_processes $!

但是您不能使用以上述方式获得的 pids 来实现安全的 "kill a whole process tree"(会话是特定类型的进程树)。

您只能杀死会话领导者的直接 children 或其整个进程组,但以这种方式被杀死的进程可能不会将终止信号进一步传递到它们的子组——这是您不能 safely/reliably 为他们做。以这种方式在会话关闭后保留下来的进程将重新设置为 init。如果他们停止了进程组,他们就没有人可以唤醒他们(这些被称为孤儿组),所以 init 将向他们发送 SIGCONTSIGHUP (这两个, SIGHUP 首先发送)。 SIGHUP 通常会杀死他们。如果他们有 SIGHUP 的处理程序,他们可能会作为守护进程继续存在。

换句话说,如果你想安全地杀死你的会话负责人的 children,请阻止那些 children 创建子组,(使你的会话 ID 始终与单个进程组匹配ID)。


*原因是在你成功 kill 你自己的 child 进程后,它变成了僵尸,直到你 wait 它,并且那个僵尸保留了 pid 点所以在您等待 child 之前,您的 child 的 pid 不是移动目标(所有其他 pids 都是)。

在 Basile Starynkevitch 的启发下,我使用了这个简单的循环,然后我在那里等待 children。

/* Searches through all directories in /proc */
while((dent = readdir(srcdir)) != NULL) {
    /* If numerical */
    if (dent->d_name[0] >= '0' && dent->d_name[0] <= '9') {
        /* Take data from /proc/[pid]/stat, see URL below for more info */
        /* http://man7.org/linux/man-pages/man5/proc.5.html */
        sprintf(path, "/proc/%s/stat", dent->d_name);
        stat_f = fopen(path,"r");
        fscanf(stat_f, "%d %*s %*c %d", &pid, &ppid);
        fclose(stat_f);
        /* Kill if shell is parent to process */
        if (shell_pid == ppid) kill(pid, SIGKILL);
    }
}