After suspending child process with SIGTSTP, shell not responding

后端 未结 4 1657
误落风尘
误落风尘 2020-12-20 19:23

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, b

相关标签:
4条回答
  • 2020-12-20 20:07

    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

    0 讨论(0)
  • 2020-12-20 20:20

    tcsetpgrp is to specify what is the foreground job. When your shell spawns a job in foreground (without &), it should create a new process group and make that the foreground job (of the controlling terminal, not whatever's on STDIN). Then, upon pressing CTRL-Z, that job will get the TSTP. It's the terminal that suspends the job, not your shell. Your shell shouldn't trap TSTP or send TSTP to anyone.

    It should just wait() for the job it has spawned and detect when it has been stopped (and claim back the foreground group and mark the job as suspended internally). Your fg command would make the job's pgid the foreground process group again and send a SIGCONT to it and wait for it again, while bg would just send the SIGCONT

    0 讨论(0)
  • 2020-12-20 20:21

    I might be late to answer the question here but this is what worked when I was stuck with the same problem. According to the man pages for tcsetpgrp()

    The function tcsetpgrp() makes the process group with process group ID pgrp the foreground process group on the terminal associated to fd, which must be the controlling terminal of the calling process, and still be associated with its session. Moreover, pgrp must be a (nonempty) process group belonging to the same session as the calling process.

    If tcsetpgrp() is called by a member of a background process group in its session, and the calling process is not blocking or ignoring SIGTTOU, a SIGTTOU signal is sent to all members of this background process group.

    So, what worked for me was ignoring the signal SIGTTOU in the shell program, before I created the processes that would come to the foreground. If I do not ignore this signal, then the kernel will send this signal to my shell program and suspend it.

    0 讨论(0)
  • 2020-12-20 20:28

    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.

    0 讨论(0)
提交回复
热议问题