Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Child process receives parent's SIGINT

Tags:

c++

c

linux

unix

I have one simple program that's using Qt Framework. It uses QProcess to execute RAR and compress some files. In my program I am catching SIGINT and doing something in my code when it occurs:

signal(SIGINT, &unix_handler);

When SIGINT occurs, I check if RAR process is done, and if it isn't I will wait for it ... The problem is that (I think) RAR process also gets SIGINT that was meant for my program and it quits before it has compressed all files.

Is there a way to run RAR process so that it doesn't receive SIGINT when my program receives it?

Thanks

like image 415
xx77aBs Avatar asked Jul 23 '11 21:07

xx77aBs


People also ask

Do children inherit signal handlers?

a child process inherits signal settings from its parent during fork (). When process performs exec (), previously ignored signals remain ignored but installed handlers are set back to the default handler.

What does child process inherit from parent in Linux?

A child process inherits most of its attributes, such as file descriptors, from its parent. In Unix, a child process is typically created as a copy of the parent, using the fork system call. The child process can then overlay itself with a different program (using exec) as required.

Does child process run before parent process?

One process is created to start executing the program. When the fork( ) system call is executed, another process is created. The original process is called the parent process and the second process is called the child process. The child process is an almost exact copy of the parent process.


1 Answers

If you are generating the SIGINT with Ctrl+C on a Unix system, then the signal is being sent to the entire process group.

You need to use setpgid or setsid to put the child process into a different process group so that it will not receive the signals generated by the controlling terminal.


[Edit:]

Be sure to read the RATIONALE section of the setpgid page carefully. It is a little tricky to plug all of the potential race conditions here.

To guarantee 100% that no SIGINT will be delivered to your child process, you need to do something like this:

#define CHECK(x) if(!(x)) { perror(#x " failed"); abort(); /* or whatever */ }
/* Block SIGINT. */
sigset_t mask, omask;
sigemptyset(&mask);
sigaddset(&mask, SIGINT);
CHECK(sigprocmask(SIG_BLOCK, &mask, &omask) == 0);

/* Spawn child. */
pid_t child_pid = fork();
CHECK(child_pid >= 0);
if (child_pid == 0) {
    /* Child */
    CHECK(setpgid(0, 0) == 0);
    execl(...);
    abort();
}
/* Parent */
if (setpgid(child_pid, child_pid) < 0 && errno != EACCES)
    abort(); /* or whatever */
/* Unblock SIGINT */
CHECK(sigprocmask(SIG_SETMASK, &omask, NULL) == 0);

Strictly speaking, every one of these steps is necessary. You have to block the signal in case the user hits Ctrl+C right after the call to fork. You have to call setpgid in the child in case the execl happens before the parent has time to do anything. You have to call setpgid in the parent in case the parent runs and someone hits Ctrl+C before the child has time to do anything.

The sequence above is clumsy, but it does handle 100% of the race conditions.

like image 77
Nemo Avatar answered Oct 18 '22 21:10

Nemo