execl()을 사용하기 시작한 «sh»는 좀비가 됩니다

execl()을 사용하기 시작한 «sh»는 좀비가 됩니다

반나절을 보냈는데 execl통화로 시작한 대시가 왜 좀비로 변했는지 아직도 알 수 없었습니다.

다음은 최소한의 테스트 사례입니다. 저는 자식을 포크하고 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당신은 자식 프로세스에 있지 않기 때문에 사소한 일이지만 좀비를 남겨두고 있습니다 .

무의미한 방식으로 STDIN을 설정했기 때문에 쉘이 즉시 종료됩니다. pipe단방향 통신 채널을 반환합니다. 도착 write하면 에서 돌아 pipefd[1]옵니다 . 셸이 파이프(STDIN)의 쓰기 측에서 읽기를 시도하도록 하는 일련의 호출을 수행합니다 .readpipefd[0]dup2

열거형의 숫자를 바꾸면 쉘이 영원히 멈추게 됩니다 read. 이것은 아마도 당신이 원하는 것이 아닐 수도 있지만 파이프를 통해 쉘이 자체적으로 연결되어 있을 때 기대할 수 있는 전부입니다.

상위 프로세스에서 쉘을 사용하려고 한다고 가정하면 이를 두 번 호출해야 합니다 pipe(부모 프로세스에서 둘 다). 사용자가 쓰는 파이프 중 하나(쉘은 stdin에서 읽음)와 쉘이 쓰는 다른 파이프 (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신호 처리기 코드의 값) 처리를 고려해야 합니다.

관련 정보