Skip to content
Advertisement

How to avoid read() from hanging in the following situation?

I have some code that forks a third-party application and redirects its standard output to the parent process, roughly as follows (no error handling here for brevity):

char* args[] = {"/path/to/3rd/party/binary", "with", "args", NULL};

int fds[2];
pipe2(fds, O_CLOEXEC);

pid_t pid = fork();
if (pid == 0)
{
    dup2(fds[1], STDOUT_FILENO);
    execvp(args[0], args);
    _exit(1);
}
else
{
    close(fds[1]);

    char buf[1024];
    int bytes_read;
    while ((bytes_read = read(fds[0], buf, sizeof buf - 1)) > 0)
    {
        buf[bytes_read] = '';
        printf("%s", buf);
    }

    close(fds[0]);
    waitpid(pid, NULL, 0);
}

I have no code for the third-party application, it is a proprietary binary. When running the third-party application in a terminal with the same arguments as used in the code above, it eventually finishes. However, when forking the third-party binary using the code above, it does not finish, but becomes a zombie process, and the code above hangs on the read() call.

The third-party binary that is forked itself forks two daemon processes (again, proprietary binaries I do not control), which I think is causing the problem here. The forked daemon processes will have a copy of the duplicated file descriptor, preventing the read() from finishing. Indeed, in case the dup2() call is replaced with:

dup3(fds[1], STDOUT_FILENO, O_CLOEXEC);

the child process finishes, but there is no output redirection to the parent process of course. Also, when the code above is modified to not do any output redirection to the parent over a pipe, the child process finishes correctly.

Is it possible to somehow prevent this hang on the read() call in this situation, or do I need to resort to some form of non-blocking I/O?

Update; using a simple popen() suffers from the same problem.

(Follow-up from: read() hangs on zombie process)

Advertisement

Answer

You need to specifically ignore SIGCHLD. It’s your responsibility to reap the zombie, but you can’t do it when blocked in read. If you call read after the SIGCHLD has been swallowed, you’ll stay in read forever.

User contributions licensed under: CC BY-SA
3 People found this is helpful
Advertisement