Home:ALL Converter>How to only kill the child process in the foreground?

How to only kill the child process in the foreground?

Ask Time:2018-05-11T03:49:08         Author:ENBYSS

Json Formatter

I am trying to build a shell, and I've managed to code most of the functionality in, however I have a small problem.

Say I type firefox &. Firefox will open up as a background process. The & activates a BG flag that makes the parent not wait for the child process.

Then I type gedit. Gedit will open as a foreground process. Meaning that currently the parent is waiting for the process to close.

At this point, the parent has two processes - firefox and gedit. Firefox hasn't been waited on, and is currently in the background, whereas we are currently waiting for Gedit to finish. So far so good.

However, if I decide to send a SIGINT signal by pressing ctrl-c, both firefox and gedit will close. Not good, only gedit should be closing.

Here is my signal handler function:

pid_t suspended_process[10];
int last_suspended = -1;

void signal_handler(int signo){
    pid_t process = currentpid();

    // Catches interrupt signal
    if(signo == SIGINT){
        int success = kill(process, SIGINT);
    }

    // Catches suspend signal
    else if(signo == SIGTSTP){
        int success = kill(process, SIGTSTP);
        resuspended = 1;
        suspended_process[last_suspended+1] = process;
        last_suspended++;
    }
}

And here's the part in fork-exec code that either waits on a process, or keeps on going.

  else if(pid > 0){ //Parent
    current_pid = pid;

    // Waits if background flag not activated.
    if(BG == 0){
      // WUNTRACED used to stop waiting when suspended
      waitpid(current_pid, &status, WUNTRACED);

        if(WIFEXITED(status)){
          setExitcode(WEXITSTATUS(status));
        }
        else if(WIFSIGNALED(status)){
          printf("Process received SIGNAL %d\n", WTERMSIG(status));
        }
    }
  }

This also happens if I suspend a process beforehand. For example, I run firefox and then press ctrl-z to suspend it. Then I run gedit and press ctrl-c to close it. Right after, if I press fg to restore the suspended firefox, it closes immediately.

I cannot find a way to only send the SIGINT signal to the foreground process, it always sends the signal to ALL children other than the parent, no matter if they are in the background, or suspended.

Just in case, this is the function that initialises the signal handler:

void init_handler(){
    struct sigaction sa;

    sa.sa_handler = signal_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART;

    // If conditions for signal handling.
    // Also creates 2 signal handlers in memory for the SIGINT and SIGTSTP
    if(sigaction(SIGINT, &sa, NULL) == -1)
        printf("Couldn't catch SIGINT - Interrupt Signal\n");
    if(sigaction(SIGTSTP, &sa, NULL) == -1)
        printf("Couldn't catch SIGTSTP - Suspension Signal\n");
}

Author:ENBYSS,eproduced under the CC 4.0 BY-SA copyright license with a link to the original source and this disclaimer.
Link to original article:https://stackoverflow.com/questions/50280498/how-to-only-kill-the-child-process-in-the-foreground
Antti Haapala -- Слава Україні :

This is rather simple, but it isn't done with signals. Instead you must use a feature called process groups. Each single job (executable or pipeline or so) will be a separate process group. You can create process groups with setpgid (or on some systems with setpgrp). You can simply set the process group of the child process after fork but before exec, and then store the process group id of this job into the job table.\n\nNow, the process group that is in the foreground is set as the active process group for the terminal (the /dev/tty of the shell) with tcsetpgrp - this is the process group that will receive CTRL+C. Those process groups that belong to the same session, but not to the group set to foreground with tcsetpgrp will be completely oblivious to CTRL+C.",
2018-05-10T20:11:44
yy