使用SIGTSTP挂起子进程后,shell没有响应
我正在用C编写一个基本的shell,现在正在暂停一个子进程 我认为我的信号处理程序是正确的,我的子进程是挂起的,但是在那之后,终端应该返回到父进程,而这不会发生 孩子被挂起,但我的shell不再注册任何输入或输出。tcsetpgrp()似乎没有帮助 以下是我的SIGTSTP shell代码中的信号处理程序:使用SIGTSTP挂起子进程后,shell没有响应,shell,process,c,signals,Shell,Process,C,Signals,我正在用C编写一个基本的shell,现在正在暂停一个子进程 我认为我的信号处理程序是正确的,我的子进程是挂起的,但是在那之后,终端应该返回到父进程,而这不会发生 孩子被挂起,但我的shell不再注册任何输入或输出。tcsetpgrp()似乎没有帮助 以下是我的SIGTSTP shell代码中的信号处理程序: void suspend(int sig) { pid_t pid; sigset_t mask; //mpid is the pgid of this shell.
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);
}
谁能告诉我我做错了什么
我是否将我的外壳与孩子一起悬挂,是否需要以某种方式将stdin和stdout返回外壳?我该怎么做
谢谢
tcsetpgrp
用于指定什么是前台作业。当您的shell在前台生成作业(没有&
)时,它应该创建一个新的进程组,并将其作为前台作业(控制终端的作业,而不是STDIN上的任何作业)。然后,在按下CTRL-Z时,该作业将获得TSTP。是终端暂停了工作,而不是你的外壳。您的shell不应该捕获TSTP或将TSTP发送给任何人
它应该只
wait()
等待它生成的作业,并在停止时检测它(并收回前台组并在内部将作业标记为挂起)。您的fg
命令将使作业的pgid再次成为前台进程组,并向其发送SIGCONT
并再次等待,而bg
将只发送SIGCONTtcsetpgrp
来指定什么是前台作业。当您的shell在前台生成作业(没有&
)时,它应该创建一个新的进程组,并将其作为前台作业(控制终端的作业,而不是STDIN上的任何作业)。然后,在按下CTRL-Z时,该作业将获得TSTP。是终端暂停了工作,而不是你的外壳。您的shell不应该捕获TSTP或将TSTP发送给任何人
它应该只wait()
等待它生成的作业,并在停止时检测它(并收回前台组并在内部将作业标记为挂起)。您的fg
命令将使作业的pgid再次成为前台进程组,并向其发送SIGCONT
并再次等待,而bg
将只发送SIGCONT这是一个老问题,但我仍然认为我找到了答案。
您没有编写家长的代码,但我假设它看起来像:
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
}
问题在于wait()或waitpid(),如果您在使用Ctrl+Z后在类似Ubuntu的操作系统上运行程序,您的子进程将获得SIGTSTP,但父进程中的wait()函数仍在等待
正确的方法是将父级中的wait()替换为pause(),并生成另一个捕获SIGCHLD的处理程序。例如:
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;
}
}
在这种情况下,在子进程接收Ctrl+Z之后,父进程也会接收SIGCHLD和pause()返回。这是一个老问题,但我仍然认为我找到了答案。
您没有编写家长的代码,但我假设它看起来像:
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
}
问题在于wait()或waitpid(),如果您在使用Ctrl+Z后在类似Ubuntu的操作系统上运行程序,您的子进程将获得SIGTSTP,但父进程中的wait()函数仍在等待
正确的方法是将父级中的wait()替换为pause(),并生成另一个捕获SIGCHLD的处理程序。例如:
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;
}
}
在这种情况下,在子进程接收到Ctrl+Z之后,父进程也会接收到SIGCHLD和pause()返回。我在这里回答这个问题可能会迟到,但当我遇到同样的问题时,这就是有效的方法。根据tcsetpgrp()的手册页
函数tcsetpgrp()使进程组具有进程组ID
pgrp与fd关联的终端上的前台进程组,
必须是呼叫过程的控制终端,以及
仍将与其会话关联。此外,pgrp必须是一个
(非空)与调用进程属于同一会话的进程组
过程
如果中后台进程组的成员调用了tcsetpgrp()
它的会话,并且调用进程没有阻塞或忽略
SIGTTOU,一个SIGTTOU信号被发送给这个背景的所有成员
进程组
因此,对我来说,在我创建将出现在前台的进程之前,忽略shell程序中的信号sigttoo
。如果我不忽略这个信号,那么内核将把这个信号发送到我的shell程序并挂起它。我在这里回答这个问题可能会迟到,但当我遇到同样的问题时,这就是有效的方法。根据tcsetpgrp()的手册页
函数tcsetpgrp()使进程组具有进程组ID
pgrp与fd关联的终端上的前台进程组,
必须是呼叫过程的控制终端,以及
仍将与其会话关联。此外,pgrp必须是一个
(非空)与调用进程属于同一会话的进程组
过程
如果中后台进程组的成员调用了tcsetpgrp()
它的会话,并且调用进程没有阻塞或忽略
SIGTTOU,一个SIGTTOU信号被发送给这个背景的所有成员
进程组
因此,对我来说,在我创建将出现在前台的进程之前,忽略shell程序中的信号sigttoo
。如果我不忽略这个信号,那么内核将把这个信号发送到我的shell程序并挂起它。我使用folk with signals使进程暂停,并用ctrl+c恢复
正在运行时的视频:
代码:
#包括
#包括
#包括
无效反向处理器(int sig);
_Bool-isPause=0;
_Bool-isRunning=1;
int main()