简体   繁体   English

SIGINT信号在Linux中重新安装

[英]SIGINT signal re-install in linux

I am writing a program dealing with Linux signals. 我正在编写一个处理Linux信号的程序。 To be more specific, I want to re-install signal SIGINT in child process, only to find that it doesn't work. 更具体地说,我想在子进程中重新安装信号SIGINT,只是发现它不起作用。

Here is a simpler version of my code: 这是我的代码的简单版本:

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;
}

When shell is printing "In child process:", I press ctrl+c. 当shell正在打印“在子进程中:”时,我按ctrl + c。 I find that function handler is executed without problem, but handler2 is never executed. 我发现执行函数handler没有问题,但是永远不会执行handler2

Could you help me with this bug in my code? 您能帮我解决代码中的这个错误吗?

Update: I want the child process to receive SIGINT signal during foo running process, is that possible? 更新:我希望子进程在foo运行过程中接收SIGINT信号,这可能吗?

It is not a bug - calling execve has replaced the running binary image. 这不是错误-调用execve替换了正在运行的二进制映像。 The function handler2() (and any other function of your binary) is no longer mapped in the program memory having been replaced by the image of "foo" and therefore all signal settings are replaced to a default. 函数handler2() (以及二进制文件的任何其他函数)不再映射到已由“ foo”映像替换的程序存储器中,因此所有信号设置均替换为默认值。

If you wish the signal handler to be active during "foo" run, you have to: 如果希望信号处理程序在“ foo”运行期间处于活动状态,则必须:

  1. make sure the handler function is mapped into the memory of foo 确保将处理函数映射到foo的内存中
  2. a signal handler is registered after "foo" starts. “ foo”开始后,将注册一个信号处理程序。

One way to do this is to create a shared library that contains the signal handler and an init function that is defined as a constructor that registers said signal handler and force it into the "foo" memory by manipulating the environment under which you execve foo (the environ variable) to include 这样做的一个方法是创建一个包含信号处理程序和共享库init被定义为一个构造寄存器所述信号处理程序,并通过操纵下,你的环境迫使它进入的“富”记忆功能execve FOO(环境变量)包括

LD_PRELOAD=/path/to/shared_library.so

@gby's anwser has given comprehensive background knowlegde. @gby的回答者提供了全面的背景知识。 I am here to give another solution without shared library. 我在这里提供没有共享库的另一种解决方案。

Every time child process stops or terminates, parent process will receive SIGCHLD. 子进程每次停止或终止时,父进程都会收到SIGCHLD。 You can handler this SIGCHLD signal to know if child process was terminated by SIGINT. 您可以处理此SIGCHLD信号,以了解子进程是否已被SIGINT终止。 In your handler: 在您的处理程序中:

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

You can get status of child process through waitpid function. 您可以通过waitpid函数获取子进程的状态。

if(WIFSIGNALED(status) && (pid == child_pid)){
    if(WTERMSIG(status) == SIGINT){
       // now you know your foo has received SIGINT.
       // do whatever you like.
    }
 }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM