faezer
faezer

Reputation: 85

SIGTSTP signal not stopping child?

I'm trying to write a program that forks, the child executes a command and then returns control to the parent. I am having trouble getting the SIGTSTP (C-z) signal to work as intended, though... I want the parent to ignore it, but the child to stop and return control to the parent, so that the child can later be resumed or killed (with a builtin command). I isolated the relevant code into a smaller program just to test it, and it seems like A) the child doesn't stop when C-z is typed, or B) it does stop, but does not return control to the parent (I'm leaning towards this because when I use cat for stdin, it behaves differently after the C-z). Here is my code.

#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <cstring>
#include <unistd.h>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <string>
#include <signal.h>


int main(){
  std::cout.setf(std::ios::unitbuf);

  std::vector<std::string> vec; vec.push_back("cat");
  std::vector<char*> chvec;
  for(unsigned int i = 0; i < vec.size(); i++){
    chvec.push_back(&vec[i][0]);
  }
  chvec.push_back(NULL);
  vec.erase(vec.begin(), vec.begin() + chvec.size());

  char** argv = &chvec[0];
  signal(SIGTSTP,SIG_IGN);

  pid_t pid;
  if((pid = fork()) == 0){
    signal(SIGTSTP,SIG_DFL);
    /*pid = getpid();
    setpgid(pid,pid);*/
    std::cout << "before exec" << std::endl;
    execvp(argv[0],argv);
    perror("exec");
  }
  else{
    //setpgid(pid,pid);
    int status;
    waitpid(pid,&status,0);
    if(WIFEXITED(status) || WIFSIGNALED(status)){
      std::cout << "exited or signaled" << std::endl;
    }
    if(WIFSTOPPED(status)){
      std::cout << "process stopped" << std::endl;
    }
    //std::cout << "process exited" << std::endl;
    pause();
  }
  return EXIT_SUCCESS;
}

Upvotes: 2

Views: 1549

Answers (1)

Sam Varshavchik
Sam Varshavchik

Reputation: 118445

It was already pointed out in the comments that you need to fix the undefined behavior as a result of the vec vector being erased. That's the first problem.

I see that your code is checking the exit status of a process using WIFSTOPPED.

Let's review the documentation for the wait(2) system call, and see what it says about this:

  WIFSTOPPED(wstatus)
         returns true if the child process was stopped by delivery  of  a
         signal;  this  is  possible only if the call was done using WUN‐
         TRACED or when the child is being traced (see ptrace(2)).

So, with that information at hand, after fixing the previously mentioned undefined behavior, and after changing your waitpid() call to:

waitpid(pid,&status,WUNTRACED);

Then I was able to send a kill -TSTP <pid> message to the spawned cat process, and obtain the expected

process stopped

message from your test program.

P.S. By stracing the child process, I could see that the child process was receiving the TSTP signal, and stopping just fine. The issue was simply that the parent wasn't handling it, without the required option to waitpid().

Upvotes: 1

Related Questions