优雅地在控制炮弹被杀死时终止进程

时间:2014-08-25 15:42:11

标签: c linux unix signals solaris

我有一个命令行应用程序。我面临的问题是,有时该应用程序的用户直接关闭运行我们的应用程序的终端,也使用以下命令:

kill -9 pid_of_parent_console

在上述情况下,我们的应用程序应该通过执行所有必要的清理来优雅地关闭。为此,我编写了一个处理SIGHUP信号的信号处理程序,因为当控制进程退出时,它将SIGHUP发送给在其下运行的进程,我们已经处理这些进程以优雅地退出我们的进程。但是,如果用户打开一个终端,假设是默认bash,然后他再次在其中键入bash命令然后运行我们的应用程序,如果假设杀死了打开终端后手动执行bash的应用程序父进程,那么我们的应用程序不会获得SIGHUP并且不会优雅地退出。为简单起见我已经编写了以下代码来重现问题:

#include <stdio.h>
#include <signal.h>

FILE *fp = NULL;
int flag = 1;

void handler(int signum)
{
    flag = 0;
}

int main()
{
    signal(SIGHUP, handler);
    // just for testing
    fp = fopen("file", "w");

    // loop terminates only when HUP is generated
    while (flag);

    // if SIGHUP is generated then code should reach here
    // and write the below in file.
    fprintf(fp, "SIGHUP Generated");

    fclose(fp);
return 0;    
}

为简单起见,我没有使用sigaction来处理信号。

我观察到的是,当我打开一个终端并按下tty命令并记下与之关联的stdin文件的名称,然后当我在同一个终端中输入bash命令时如果我记下stdin文件使用tty命令与它相关联,我发现两个bash shell,一个在我启动终端时默认打开,另一个是我通过在bash控制台中键入bash命令手动打开共享相同的stdin文件名。

因此,当我杀死第二个bash时,我的进程的父节点与之关联的stdin文件没有关闭,我认为这就是为什么我没有收到SIGHUP信号。

当控制台被杀时,我还能用其他任何方法来优雅地杀死我的进程。

使用的终端仿真器:GNOME终端2.31.3 默认shell:bash

1 个答案:

答案 0 :(得分:1)

无论操作系统如何,SIGKILL(即信号-9)都由内核直接处理,并且在任何用户空间处理程序有机会处理任何内容之前,进程将被终止。 Linux内核就像Solaris Solaris一样。

目标进程无法保护自己免受该信号的攻击(在发送方或内核中拦截它之外)。

另一方面,关闭终端仿真器窗口会向其发送XEvent。在退出之前,终端仿真器应该向您的进程发送一个SIGHUP信号。

我建议在Solaris 10计算机上使用dtrace来调查此过程。从此脚本开始,显示发送的所有信号:http://www.brendangregg.com/DTrace/kill.d