1

I am trying to understand processes in C. I currently want to create shell-like structure which - after pressing a shortcut like Ctrl+C or Ctrl+Z will kill all its subprocesses but will stay alive. My code looks like this:

#include <ctype.h>
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <readline/readline.h>
#include <readline/history.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/wait.h>
#include <termios.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/signal.h>

pid_t pid;

void send_signal(int signum){
  kill(pid, signum);
}

void init_signals(){
  signal(SIGINT, send_signal);
  signal(SIGTSTP, send_signal);
}

int main(){
    init_signals();
    pid = fork();
  if(pid > 0){
    //Parent Process
    wait(NULL);
  } else {
    // Child Process
    while(1){
        usleep(300000);
    }   

  }

  return 0;
}

Problem here is that, when I press Ctrl+C, parent redirects it to child and kills it but when I press Ctrl+Z (even though child process is stopped) parent still hangs on wait(NULL). Any suggestions on how to fix this?

L Y E S - C H I O U K H
  • 4,765
  • 8
  • 40
  • 57
Giorgi Cercvadze
  • 403
  • 1
  • 7
  • 23

2 Answers2

1

You can check here how to use wait in C . Long story short:

The wait system-call puts the process to sleep and waits for a child-process to end. It then fills in the argument with the exit code of the child-process (if the argument is not NULL).

wait doesn't get signaled until the child process ends, so just by sending the child to sleep there is no reason for the main process to continue. If you want any setup where the main process still works while the child does as well (including when it sleeps!) you can't wait on the child.

Wouldn't make sense for a shell either - it's always active in the background. Instead you need a better handler on main - like waiting on a condition. That way, when sending a child to sleep, you can signal the condition and keep going.

kabanus
  • 24,623
  • 6
  • 41
  • 74
  • "wait doesn't get signaled until the child process ends, so just by sending the child to sleep there is no reason for the main process to continue." I am not sending child to sleep I am stopping the child with Ctrl+Z, why doesn't it end ? – Giorgi Cercvadze Mar 16 '18 at 20:39
  • @GeorgeTsertsvadze Stopping/sending to sleep same thing in this context. As long as it's alive, it doesn't end. To be clear Ctrl-Z **does not kill a process**. The process is still alive - and thus wait will still block. – kabanus Mar 16 '18 at 20:45
  • Try it in a shell - start some process, then press Ctrl-Z. Now hit fg and enter - the process will continue where it stopped - since it was alive all the time. In fact, in your program you can use `SIGCONT` to let it continue running after stopped. Essentially like waiting on a condition. Not dying. – kabanus Mar 16 '18 at 20:46
0

Apart from the solution at https://stackoverflow.com/a/49346549/5694959 I would like to suggest one more solution as to handle signals for parent process only.This way parent will execute signal handler and default action will be performed for child process. Use waitpid() to get the status of child.

waitpid(pid, NULL, WUNTRACED);

Now parent will resume its execution when child process changes its state i.e. either terminated or stopped.

Update your code as follows:

#include <ctype.h>
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <readline/readline.h>
#include <readline/history.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/wait.h>
#include <termios.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/signal.h>

pid_t pid;

void send_signal(int signum){
  kill(pid, signum);
}

void init_signals(){
  signal(SIGINT, send_signal);
  signal(SIGTSTP, send_signal);
}

int main(){

    pid = fork();
  if(pid > 0){
    //Parent Process
    init_signals();
    waitpid(pid, NULL, WUNTRACED);
    printf("I think this is what you are expecting...\n");
  } else {
    // Child Process
    while(1){
        usleep(300000);
    }   

  }

  return 0;
}

Just one thing to keep in mind that please make sure that parent process has handled signal before you press ctrl + c or ctrl + z otherwise, default action of signal will be performed for parent as well.

Developer Guy
  • 2,318
  • 6
  • 19
  • 37
Monk
  • 756
  • 5
  • 16