使用 execl() 启动的 «sh» 变成了僵尸

使用 execl() 启动的 «sh» 变成了僵尸

我花了半天时间,还是想不通,为什么用execlcall启动的dash就变成了僵尸。

下面是一个最小的测试用例 - 我只是分叉一个孩子,复制 std[输入、输出、错误]描述符,并启动

#include <cstdio>
#include <fcntl.h>
#include <cstring>
#include <stdlib.h>
#include <cerrno>
#include <unistd.h>

int main() {
    int pipefd[2];
    enum {
        STDOUT_TERM = 0,
        STDIN_TERM  = 1
    };
    if (pipe(pipefd) == -1) { //make a pipe
        perror("pipe");
        return 0;
    }
    pid_t pid = fork();
    if (pid == 0)
    {// Child
        dup2(pipefd[STDIN_TERM], STDIN_FILENO);
        dup2(pipefd[STDOUT_TERM], STDOUT_FILENO);
        dup2(pipefd[STDOUT_TERM], STDERR_FILENO);
        execl("/bin/sh","sh", (char*)NULL);
        // Nothing below this line should be executed by child process. If so, print err
        perror("For creating a shell process");
        exit(1);
    }
    __asm("int3");
    puts("Child launched");
}

当我在调试器中启动它时,在带有断点的行处(通话上方puts()看着那(这PID变量,然后用 ps 查看相应的过程,我每次都会得到类似的东西

2794 pts/10   00:00:00 sh <defunct>

即它是一个僵尸

答案1

你正在留下一个僵尸,微不足道,因为你没有wait在你的子进程上。

你的 shell 会立即退出,因为你以一种无意义的方式设置了它的 STDIN。pipe返回单向通信通道。你write到,pipefd[1]read从 回来pipefd[0]。您执行了一系列dup2调用,导致 shell 尝试从管道的写入端读取 (STDIN)。

一旦你交换了枚举中的数字,你的 shell 就会永远停留在read.这可能也不是您想要的,但是当您有一个通过管道连接到自身的 shell 时,这就是您所能期望的一切。

假设您尝试使用父进程中的 shell,则需要调用pipe两次(并且都在父进程中):您写入的管道之一(shell 在 stdin 上读取)和 shell 写入的另一个管道到 (stdout/stderr) 并从中读取。或者,如果您愿意,socketpair也可以使用。

答案2

您需要捕获 SIGCHLD 信号,并通过wait()系统调用“收割”僵尸进程。向程序中添加几乎最少的代码即可添加信号处理函数,并将其设置为 SIGCHLD 处理程序,如下所示:

#include <cstdio>
#include <fcntl.h>
#include <cstring>
#include <stdlib.h>
#include <cerrno>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>

void sighandler(int signal_number);

void sighandler(int signo) {
    if (signo == SIGCHLD) {
            int status;
            (void)wait(&status);
    }
}


int main() {
    int pipefd[2];
    enum {
        STDOUT_TERM = 0,
        STDIN_TERM  = 1
    };
    signal(SIGCHLD, sighandler);
    pid_t pid = fork();

您几乎肯定应该检查系统调用的返回状态signal(),并考虑处理子进程的退出状态(status信号处理程序代码中的值)。

相关内容