Child process receives parent's SIGINT - c++

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

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.

What are you doing in your handler? There are only certain Qt functions that you can call safely from a unix signal handler. This page in the documentation identifies what ones they are.
The main problem is that the handler will execute outside of the main Qt event thread. That page also proposes a method to deal with this. I prefer getting the handler to "post" a custom event to the application and handle it that way. I posted an answer describing how to implement custom events here.

Just make the subprocess ignore SIGINT:
child_pid = fork();
if (child_pid == 0) {
/* child process */
signal(SIGINT, SIG_IGN);
execl(...);
}
man sigaction:
During an execve(2), the dispositions of handled signals are reset to the default;
the dispositions of ignored signals are left unchanged.

Related

How to kill/signal other child processes from another child process?

I am having a bit of trouble figuring out exactly how the kill(pid_t pid, int sig) function works when using it in a child process. In my program, I have the parent, and 8 child processes created with fork(). I've been searching and reading online to no avail unfortunately. All of the searched yield results about killing children from the parent process.
I have signal handlers set up in each process, except they are not working correctly.
Basically, I need to signal all of the processes in the process group from the child process "signal_generating_process", but for some reason the signals are not going through correctly.
On the man page, kill(2) says that if I use 0 as the first argument, it will send the signal to all processes in the process group, but its not working correctly for me. I'll include the code for the signal generator as well as one of the signal handlers. Feel free to ask for more information if I haven't included enough. Thank you all very much!
void signal_generating_process(){
signal(SIGINT, end_process_handler);
block_sigusr1();
block_sigusr2();
while(true){
millisleep(randomFloat(.01,.1)); //function I created to sleep for a certain amount of milliseconds
int sig = rand_signal(); //randomly picks between sigusr1 and sigusr2
kill(0, sig);
if(sig == SIGUSR1){ //adds to a counter for sigusr1
pthread_mutex_lock(&shm_ptr->mutex1_sent);
shm_ptr->SIGUSR1_sent++;
pthread_mutex_unlock(&shm_ptr->mutex1_sent);
}
else{ //signal == SIGUSR2 - adds to a counter for sigusr2
pthread_mutex_lock(&shm_ptr->mutex2_sent);
shm_ptr->SIGUSR2_sent++;
pthread_mutex_unlock(&shm_ptr->mutex2_sent);
}
}
}
Process that handles sigusr1 and the signal handler (sigusr2 is the same):
void sigusr1_receiving_process(){
block_sigusr2();
signal(SIGUSR1, sigusr1_handler);
signal(SIGINT, end_process_handler);
while(true){
sleep(1);
}
}
void sigusr1_handler(int signal){
printf("Signal 1 Received\n");
if(signal == SIGUSR1){
pthread_mutex_lock(&shm_ptr->mutex1_received);
shm_ptr->SIGUSR1_received++;
pthread_mutex_lock(&shm_ptr->mutex1_received);
}
}
When these loops go through, "Signal 1 Received" is never printed throughout the course of the entire execution. Is there anything that you can tell is obviously wrong with how I'm handling signals?
Edit: I fixed my problem! Unfortunately, it had nothing to do with what I have above, so I apologize for people who find this question in the future looking for an answer.
Anyway, if you do stumble upon it, maybe it has to do with the way you block signals. I blocked signals incorrectly in the parent process, so they transferred over into the child processes. If you're having this issue, maybe check how you have blocked signals.

Waiting in Background process in C program in Unix

Im trying to emulate shell through C program. In my program whenever I run any normal (foreground) commands it works fine. Also I have handled background process with commands ending with '&'. Now to handle this I have avoided the parent waiting for a child process.
The problem is whenever for the first time in my shell I run any background command(i.e ending in '&') then it works fine. But then after that each command(normal) doesnot terminate. I guess it waits for the previously opened process. How to rectify. Please you can ask questions so that i can make myself more clear to you. This is the snippet which is doing the above mentioned task.
child_id=fork();
if(child_id==0){
//logic fo creating command
int ret=execvp(subcomm[0],subcomm);
}
//Child will never come here if execvp executed successfully
if(proc_sate!='&'){
for(i=0;i<count_pipe+1;i++){
waitpid(0,&flag,0);
}
//something to add to make it not wait for other process in my scenario for second time
}
Here proc_state just determines whether it is background or foreground.It is just a character. count_pipe is just a variable holding number of pipes (e.g ls -l|wc|wc this contains 2 pipes). Dont worry this all is working fine.
waitpid(0, &flag, 0) waits for any child process whose process group ID is equal to that of your shell. So if you have not called setsid() after the fork() of the disconnected child process, the code above will wait for that too.
pid_t pid = fork();
if (pid == 0) { /* child process */
setsid(); /* Child creates new process group */
... /* redirections, etc */
execvp(...);
}

Cancelling thread that is stuck on epoll_wait

I'm doing some event handling with C++ and pthreads. I have a main thread that reads from event queue I defined, and a worker thread that fills the event queue. The queue is of course thread safe.
The worker thread have a list of file descriptors and create an epoll system call to get events on those file descriptors. It uses epoll_wait to wait for events on the fd's.
Now the problem. Assuming I want to terminate my application cleanly, how can I cancel the worker thread properly? epoll_wait is not one of the cancellation points of pthread(7) so it cannot react properly on pthread_cancel.
The worker thread main() looks like this
while(m_WorkerRunning) {
epoll_wait(m_EpollDescriptor, events, MAXEVENTS, -1);
//handle events and insert to queue
}
The m_WorkerRunning is set to true when the thread starts and it looks like I can interrupt the thread by settings m_WorkerRunning to false from the main thread. The problem is that epoll_wait theoretically can wait forever.
Other solution I though about is: instead of waiting forever (-1) I can wait for example X time slots, then handle properly no-events case and if m_WorkerRunning == false then exit the loop and terminate the worker thread cleanly. The main thread then sets m_WorkerRunning to false, and sleeps X. However I'm not sure about the performance of such epoll_wait and also not sure what would be the correct X? 500ms? 1s? 10s?
I'd like to hear some experienced advises!
More relevant information: the fd's I'm waiting events on, are devices in /dev/input so technically I'm doing some sort of input subsystem. The targeted OS is Linux (latest kernel) on ARM architecture.
Thanks!
alk's answer above is almost correct. The difference, however, is very dangerous.
If you are going to send a signal in order to wake up epoll_wait, never use epoll_wait. You must use epoll_pwait, or you might run into a race with your epoll never waking up.
Signals arrive asynchronously. If your SIGUSR1 arrives after you've checked your shutdown procedure, but before your loop returns to the epoll_wait, then the signal will not interrupt the wait (as there is none), but neither will the program exit.
This might be very likely or extremely unlikely, depending on how long the loop takes in relation to how much time is spent in the wait, but it is a bug one way or the other.
Another problem with alk's answer is that it does not check why the wait was interrupted. It might be any number of reasons, some unrelated to your exit.
For more information, see the man page for pselect. epoll_pwait works in a similar way.
Also, never send signals to threads using kill. Use pthread_kill instead. kill's behavior when sending signals is, at best, undefined. There is no guarantee that the correct thread will receive it, which might cause an unrelated system call to be interrupted, or nothing at all to happen.
You could send the thread a signal which would interupt the blocking call to epoll_wait(). If doing so modify your code like this:
while(m_WorkerRunning)
{
int result = epoll_wait(m_EpollDescriptor, events, MAXEVENTS, -1);
if (-1 == result)
{
if (EINTR == errno)
{
/* Handle shutdown request here. */
break;
}
else
{
/* Error handling goes here. */
}
}
/* Handle events and insert to queue. */
}
A way to add a signal handler:
#include <signal.h>
/* A generic signal handler doing nothing */
void signal_handler(int sig)
{
sig = sig; /* Cheat compiler to not give a warning about an unused variable. */
}
/* Wrapper to set a signal handler */
int signal_handler_set(int sig, void (*sa_handler)(int))
{
struct sigaction sa = {0};
sa.sa_handler = sa_handler;
return sigaction(sig, &sa, NULL);
}
To set this handler for the signal SIGUSR1 do:
if (-1 == signal_handler_set(SIGUSR1, signal_handler))
{
perror("signal_handler_set() failed");
}
To send a signal SIGUSR1 from another process:
if (-1 == kill(<target process' pid>, SIGUSR1))
{
perror("kill() failed");
}
To have a process send a signal to itself:
if (-1 == raise(SIGUSR1))
{
perror("raise() failed");
}

c++ fork, without wait, defuncts execl

Looking to fork a process, in c++, that wont hang its parent process - its parent is a daemon and must remain running. If i wait() on the forked process the forked execl wont defunt - but - it will also hang the app - not waiting fixes the app hang - but the command becomes defunt.
if((pid = fork()) < 0)
perror("Error with Fork()");
else if(pid > 0) {
//wait here will hang the execl in the parent
//dont wait will defunt the execl command
//---- wait(&pid);
return "";
} else {
struct rlimit rl;
int i;
if (rl.rlim_max == RLIM_INFINITY)
rl.rlim_max = 1024;
for (i = 0; (unsigned) i < rl.rlim_max; i++)
close(i);
if(execl("/bin/bash", "/bin/bash", "-c", "whoami", (char*) 0) < 0) perror("execl()");
exit(0);
}
How can I fork the execl without a wait(&pid) where execl's command wont defunct?
UPDATE
Fixed by adding the following before the fork
signal(SIGCHLD, SIG_IGN);
Still working with my limited skills at a more compatible solution based on the accepted answer. Thanks!
By default, wait and friends wait until a process has exited, then reap it. You can call waitpid with the WNOHANG to return immediately if no child has exited.
The defunct/"zombie" process will sit around until you wait on it. So if you run it in the background, you must arrange to reap it eventually by any of several ways:
try waitpid with WNOHANG routinely: int pid = waitpid(-1, &status, WNOHANG)
install a signal handler for SIGCHLD to be notified when it exits
Additionally, under POSIX.1-2001, you can use sigaction set the SA_NOCLDWAIT on SIGCHLD. Or set its action to SIG_IGN. Older systems (including Linux 2.4.x, but not 2.6.x or 3.x) don't support this.
Check your system manpages, or alternative the wait in the Single Unix Specification. The Single Unix Spec also gives some helpful code examples. SA_NOCLDWAIT is documented in sigaction.
I think a signal handler would be the best way as indicated. I would like to point out another way this could be handled: Fork twice and have the child exit while the grandchild would call execl. The defunct process would then be cleaned up by the init process.
As said in comment, double fork saves process from defunct state.
What is the reason for performing a double fork when creating a daemon?

c++ fork() & execl() dont wait, detach completely

So I have a simple fork and exec program. It works pretty good but I want to be able to detach the process that is started, I try a fork with no wait:
if((pid = fork()) < 0)
perror("Error with Fork()");
else if(pid > 0) {
return "";
}
else {
if(execl("/bin/bash", "/bin/bash", "-c", cmddo, (char*) 0) < 0) perror("execl()");
exit(0);
}
It starts the proc fine but when my main app is closed - so is my forked proc.
How do I keep the forked process running after the main proc (that started it) closes?
Thanks :D
Various things to do if you want to start a detached/daemon process:
fork again and exit the first child (so the second child process no longer has the original process as its parent pid)
call setsid(2) to get a new session and process group
reopen stdin/stdout/stderr to dereference the controlling tty, if there was one. Or, for example, you might have inherited a pipe stdout that will be broken and give you SIGPIPE if you try to write it.
chdir to / to get away from the ancestor's current directory
Probably all you really want is to ignore SIGHUP in your fork()ed process as this is normally the one which brings the program down. That is, what you need to do is
signal(SIGHUP, SIG_IGN);
Using nohup arranges for a reader to be present which would avoid possibly writing to close pipe. To avoid this you could either arrange for standard outputs not to be available or to also ignore SIGPIPE. There are a number of signals which terminate your program when not ignore (see man signal; some signals can't be ignored) but the one which will be sent to the child is is SIGHUP.