SIGTSTP 信号没有停止 child?
SIGTSTP signal not stopping child?
我正在尝试编写一个分叉的程序,child 执行一个命令,然后 return 将控制权交给 parent。我无法让 SIGTSTP (C-z) 信号按预期工作,但是......我希望 parent 忽略它,但 child 停止并且 return 控制权交给 parent,以便 child 稍后可以恢复或终止(使用内置命令)。我将相关代码隔离到一个较小的程序中只是为了测试它,看起来 A) child 在键入 C-z 时不会停止,或者 B) 它确实停止,但不会 return 控制到 parent(我倾向于这个,因为当我将 cat 用于标准输入时,它在 C-z 之后表现不同)。这是我的代码。
#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;
}
评论中已经指出,您需要修复由于删除 vec
矢量而导致的未定义行为。这是第一个问题。
我看到您的代码正在使用 WIFSTOPPED
检查进程的退出状态。
让我们review the documentation for the wait(2)
system call,看看它是怎么说的:
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)).
因此,根据手头的信息,在修复前面提到的未定义行为并将您的 waitpid()
调用更改为:
之后
waitpid(pid,&status,WUNTRACED);
然后我能够向派生的 cat
进程发送 kill -TSTP <pid>
消息,并获得预期的
process stopped
来自您的测试程序的消息。
P.S。通过跟踪 child 进程,我可以看到 child 进程正在接收 TSTP
信号,并且停止得很好。问题很简单,parent 没有处理它,没有 waitpid()
.
所需的选项
我正在尝试编写一个分叉的程序,child 执行一个命令,然后 return 将控制权交给 parent。我无法让 SIGTSTP (C-z) 信号按预期工作,但是......我希望 parent 忽略它,但 child 停止并且 return 控制权交给 parent,以便 child 稍后可以恢复或终止(使用内置命令)。我将相关代码隔离到一个较小的程序中只是为了测试它,看起来 A) child 在键入 C-z 时不会停止,或者 B) 它确实停止,但不会 return 控制到 parent(我倾向于这个,因为当我将 cat 用于标准输入时,它在 C-z 之后表现不同)。这是我的代码。
#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;
}
评论中已经指出,您需要修复由于删除 vec
矢量而导致的未定义行为。这是第一个问题。
我看到您的代码正在使用 WIFSTOPPED
检查进程的退出状态。
让我们review the documentation for the wait(2)
system call,看看它是怎么说的:
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)).
因此,根据手头的信息,在修复前面提到的未定义行为并将您的 waitpid()
调用更改为:
waitpid(pid,&status,WUNTRACED);
然后我能够向派生的 cat
进程发送 kill -TSTP <pid>
消息,并获得预期的
process stopped
来自您的测试程序的消息。
P.S。通过跟踪 child 进程,我可以看到 child 进程正在接收 TSTP
信号,并且停止得很好。问题很简单,parent 没有处理它,没有 waitpid()
.