Reputation: 85
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
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