shell - 使用 SIGTSTP 挂起子进程后,shell 没有响应

标签 shell process c signals

我正在用 C 编写一个基本的 shell,我现在正致力于暂停一个子进程。

我认为我的信号处理程序是正确的,我的子进程正在挂起,但在那之后,终端应该返回到父进程,而这并没有发生。

child 被挂起,但我的 shell 不再注册任何输入或输出。 tcsetpgrp() 似乎没有帮助。

这是我的 SIGTSTP 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);
}

谁能告诉我我做错了什么?

我是否将我的 shell 与子进程一起暂停,我是否需要以某种方式将 stdin 和 stdout 返回给 shell?我该怎么做?

谢谢!

最佳答案

这是一个老问题,但我仍然认为我找到了答案。
你没有写你 parent 的代码,但我假设它看起来像:

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() 函数仍在等待!

这样做的正确方法是用 pause() 替换父级中的 wait(),并创建另一个捕获 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() 返回。

关于shell - 使用 SIGTSTP 挂起子进程后,shell 没有响应,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12664664/

相关文章:

linux - 如何在不使用 echo 的情况下更改输出颜色?

linux - linux中如何删除超过n天的文件和目录

shell - 如何通过Go运行此命令?

c# - 无法从 GetProcessId(.. hWnd) (pInvoke) 中提取进程 ID

linux - 父进程能否知道子进程是否在coredumping

c# - 在 wpf 应用程序中运行其他控制台进程之前如何等待控制台进程完成?

java - void 变量有什么用?

sql - 通过 shellscript 将 CSV 导入 SQLite,主键问题和重复数据

c - 数据类型 - 溢出

c - C指针的问题