Shuai Zhang
Shuai Zhang

Reputation: 2061

SIGINT signal re-install in linux

I am writing a program dealing with Linux signals. To be more specific, I want to re-install signal SIGINT in child process, only to find that it doesn't work.

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. I find that function handler is executed without problem, but handler2 is never executed.

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?

Upvotes: 0

Views: 471

Answers (2)

gby
gby

Reputation: 15218

It is not a bug - calling execve has replaced the running binary image. 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.

If you wish the signal handler to be active during "foo" run, you have to:

  1. make sure the handler function is mapped into the memory of foo
  2. a signal handler is registered after "foo" starts.

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

LD_PRELOAD=/path/to/shared_library.so

Upvotes: 2

Sky Dragon
Sky Dragon

Reputation: 9

@gby's anwser has given comprehensive background knowlegde. I am here to give another solution without shared library.

Every time child process stops or terminates, parent process will receive SIGCHLD. You can handler this SIGCHLD signal to know if child process was terminated by 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.

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

Upvotes: 0

Related Questions