How to set the paused process to background?

2019-08-05 09:38发布

问题:

I am new in C. I am trying to make a shell - like program. I am currently making a signal handler, which means, when the process is running and somebody pressed ctrl + Z the process should pause and go to background while shell has to continue. The problem here is: parent process is making wait(NULL), but child is not ending the program so basically parent waits the child which is not ending the program yet. How to make it so that parent continues to work foreground. (you can see my code How to redirect signal to child process from parent process? here)

回答1:

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.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
                printf("PARENT: %d\n", getpid());
                waitpid(pid, NULL, WUNTRACED);
                printf("Parent out of wait, i think this is what you are expecting\n");
        } else {
                struct sigaction act = {{0}};
                act.sa_handler = send_signal;
                act.sa_flags = SA_RESETHAND;
                sigaction(SIGTSTP, &act, NULL);
                sigaction(SIGINT, &act, NULL);
                perror("sigaction ");
                printf("CHILD: %d\n", getpid());
                // Child Process
                while(1){
                        usleep(300000);
                }
        }
        return 0;
}

I think above code can serve your purpose. Let me explain it.

In your code [How to redirect signal to child process from parent process? you have handled signal and from hander context sending same signal.When you pressed Ctrl + c or Ctrl + z both parent and child receives signal. Now as per the handler code

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

when handler will execute in parent's context pid will be equal to child's pid so it will send signal to child but when handler runs in child context pid value will be 0, so it sends signal to whole process group i.e. parent as well as child. this make you code to run handler recursively for infinite times. Due to this you are not getting desired result.

I have modified two things to get desired result.

child context

In child context restore the signal action to the default upon entry to the signal handler so that when child receives signal for second time signal default action can be performed.

parent context

use waitpid() instead of wait().

pid_t waitpid(pid_t pid, int *status, int options);

The waitpid() system call suspends execution of the calling process until a child specified by pid argument has changed state.  By  default, waitpid() waits only for terminated children, but this behavior is modifiable via the options argument.

`WUNTRACED`   also  return  if  a child has stopped

Due to WUNTRACED parent process will return when child will be stopped or terminated.

I hope it will serve you purpose ask me if it don't.