After suspending child process with SIGTSTP, shell not responding

10,268

Solution 1

It's an old question but still I think I found an answer.
You didn't write your parent's code but I'm assuming its looks something like:

int main(){ 
     pid_t pid = fork();
     if(pid == 0){ //child process
        //call some program
     else //parent process
        wait(&status); //or waitpid(pid, &status, 0)
        //continue with the program
}

the problem is with the wait() or waitpid(), it's look like if you run your program on OS like Ubuntu after using Ctrl+Z your child process is getting the SIGTSTP but the wait() function in the parent process is still waiting!

The right way of doing that is to replace the wait() in the parent with pause(), and make another handler that catch SIGCHLD. For example:

void sigHandler(int signum){
     switch(signum){
        case SIGCHLD:
             // note that the last argument is important for the wait to work
             waitpid(-1, &status, WNOHANG);
             break;
     }
}

In this case after the child process receive Ctrl+Z the parent process also receive SIGCHLD and the pause() return.

Solution 2

i used folk with signals for make process pause and resume with ctrl+c

video while is running : link

Code:

#include <stdio.h>
#include <unistd.h>
#include <signal.h>

void reverse_handler(int sig);
_Bool isPause=0;
_Bool isRunning=1;

int main()
{
    int ppid;
    int counter=0;
    //make parent respond for ctrl+c (pause,resume).
    signal(SIGINT,reverse_handler);
    while(isRunning){
        while(isPause==0)
        {
            /*code exec while process is resuming */
            printf("\nc:%d",counter++);
            fflush(stdout);
            sleep(1);
        }
        //close parent after child is alive.
        if((ppid=fork())==0){   exit(0);    }
        //make child respond for ctrl+c (pause,resume).
        signal(SIGINT,reverse_handler);
        //keep child alive and listening.
        while(isPause==1){ /*code exec while process is pausing */  sleep(1);   }
    }
    return 0;
}
//if process is pause made it resume and vice versa.
void reverse_handler(int sig){
    if(isPause==0){
        printf("\nPaused");
        fflush(stdout);
        isPause=1;
    }
    else if(isPause==1){
        printf("\nresuming");
        fflush(stdout);
        isPause=0;
    }
}

i hope that's be useful.

please comment me if there's any questions

Share:
10,268
user1710304
Author by

user1710304

Updated on June 16, 2022

Comments

  • user1710304
    user1710304 almost 2 years

    I'm coding a basic shell in C, and I'm working on suspending a child process right now.

    I think my signal handler is correct, and my child process is suspending, but after that, the terminal should return to the parent process and that's not happening.

    The child is suspended, but my shell isn't registering any input or output anymore. tcsetpgrp() doesn't seem to be helping.

    Here's my signal handler in my shell code for SIGTSTP:

    void suspend(int sig) {
        pid_t pid;
        sigset_t mask;
        //mpid is the pgid of this shell.
        tcsetpgrp(STDIN_FILENO, mpid);
        tcsetpgrp(STDOUT_FILENO, mpid);
        sigemptyset(&mask);
        sigaddset(&mask, SIGTSTP);
        sigprocmask(SIG_UNBLOCK, &mask, NULL);
        signal(SIGTSTP, SIG_DFL);
        //active.pid is the pid of the child currently in the fg.
        if (active.pid != 0) {
            kill(active.pid, SIGTSTP);
        }
        else{
            //if this code is being run in the child, child calls SIGTSTP on itself.
            pid = getpid();
            if (pid != 0 && pid != mpid){
                kill(pid, SIGTSTP);
            }
        }
        signal(SIGTSTP, suspend);
    }
    

    Can anyone tell me what I'm doing wrong?

    Am I suspending my shell along with the child, and do I need to return stdin and stdout to the shell somehow? How would I do this?

    Thanks!

  • user1710304
    user1710304 over 11 years
    Thanks for the reply. I've tried doing what you say, but when I take away my signal handler the terminal just suspends the parent and returns to bash. I need the parent to keep running.
  • Fingolfin
    Fingolfin over 11 years
    This is plain wrong, not catching SIGTSTP would certainly cause his shell to suspend and will let the children processes go on. He needs to catch it so his shell won't suspend. I am facing the same problem right now he faced earlier
  • Stephane Chazelas
    Stephane Chazelas over 11 years
    @AdelQodmani, only the foreground process group of the terminal receives a SIGTSTP when you press <kbd>Ctrl-Z</kbd>. The shell which is just waiting for the termination of the process it started, is in a process group that is not the foreground process group of the terminal. you can ignore SIGTSTP if you like, that's probable what most shells do. My point was that you need to play with the foreground process group of the terminal.