Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

After suspending child process with SIGTSTP, shell not responding

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!

like image 721
user1710304 Avatar asked Oct 01 '12 03:10

user1710304


People also ask

How do you handle Sigtstp?

It cannot be handled, ignored, or blocked. The SIGTSTP signal is an interactive stop signal. Unlike SIGSTOP , this signal can be handled and ignored. Your program should handle this signal if you have a special need to leave files or system tables in a secure state when a process is stopped.

How do I send Sigtstp signal?

Pressing Ctrl+Z sends a STOP signal (SIGTSTP) to the process which kind of freezes/pauses the process and the shell prompt returns.

How do I suspend a child in Linux?

It is quite an easy job to suspend a process in Linux. In UNIX, by typing 'Ctrl+Z', you can suspend the job that is currently connected to your terminal. The command prompt will notify you that the process has been stopped. It will assign a process ID to the suspended job.

Which signal does the bg command send to a suspended process for redemption?

The shell will then mark that job as a background job in its memory and treat it accordingly, and send SIGCONT if it sees that it's currently stopped. The bg command doesn't itself send a signal, but the shell might send SIGCONT as a reaction to bg .


2 Answers

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.

like image 144
DavidDr90 Avatar answered Sep 26 '22 02:09

DavidDr90


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

like image 29
Mahmoud shahin Avatar answered Sep 25 '22 02:09

Mahmoud shahin