0

我正在编写一个处理 Linux 信号的程序。更具体地说,我想在子进程中重新安装信号 SIGINT,却发现它不起作用。

这是我的代码的更简单版本:

void handler(int sig){
    //do something
    exit(0);
}

void handler2(int sig){
    //do something
    exit(0);
}
int main(){

    signal(SIGINT, handler);

    if ((pid = fork()) == 0) {
        signal(SIGINT, handler2); // re-install signal SIGINT

        // do something that takes some time
        printf("In child process:\n");
        execve("foo", argv, environ); // foo is a executable in local dir

        exit(0);
    }else{
        int status;
        waitpid(pid, &status, 0); // block itself waiting for child procee to exit
    }

    return 0;
}

当 shell 打印“在子进程中:”时,我按 ctrl+c。我发现该函数handler执行没有问题,但handler2从未执行。

你能帮我解决我代码中的这个错误吗?

更新:我希望子进程在foo运行过程中接收 SIGINT 信号,这可能吗?

4

2 回答 2

1

这不是一个错误 - 调用execve已经取代了正在运行的二进制图像。该函数handler2()(以及二进制文件的任何其他函数)不再映射到已被“foo”图像替换的程序内存中,因此所有信号设置都被替换为默认值。

如果您希望信号处理程序在“foo”运行期间处于活动状态,您必须:

  1. 确保处理函数映射到 foo 的内存中
  2. 在“foo”启动后注册一个信号处理程序。

一种方法是创建一个共享库,其中包含信号处理程序和一个init定义为构造函数的函数,该构造函数注册所述信号处理程序并通过操纵您execvefoo 所在的环境(环境变量)包括

LD_PRELOAD=/path/to/shared_library.so
于 2013-10-07T08:23:41.453 回答
0

@gby 的回答者提供了全面的背景知识。我在这里提供另一个没有共享库的解决方案。

每次子进程停止或终止时,父进程都会收到 SIGCHLD。您可以处理此 SIGCHLD 信号以了解子进程是否被 SIGINT 终止。在您的处理程序中:

pid_t pid = waitpid(pid_t pid,int * status,int options)

您可以通过 waitpid 函数获取子进程的状态。

if(WIFSIGNALED(status) && (pid == child_pid)){
    if(WTERMSIG(status) == SIGINT){
       // now you know your foo has received SIGINT.
       // do whatever you like.
    }
 }
于 2014-07-05T05:03:10.813 回答