Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are stdin/stderr guaranteed to be closed after process terminates?

Tags:

c

posix

I spawn a child process using pipe(), fork(), dup(), execve().

From the parent, is it safe to wait for stdin and stdout of the child to close (i.e. read() return 0 on both), and then do waitpid() to collect the termination status?

Or can it happen that the process will fail without ever closing stdin and stdout? (thus my program never getting to waitpid)


To clarify, I'm asking whether the following is safe:

while (child_stdin != -1 && child_stdout != -1) {
    poll(...)

    if (got_stdout) {
        n = read(child_stdout);
        if (n >= 0) {
            // do something with output
        } else if (n == 0) {
            child_stdout = -1
        }
    }

    // same for stdin
}

waitpid(child_pid)

Or can it happen that child will terminate, but I'll never get 0 on read() or write().

No signals are involved, just poll()-ing.

like image 377
Jaka Jančar Avatar asked Nov 01 '12 17:11

Jaka Jančar


People also ask

Can you close stdin?

Closing stdin by pressing Ctrl+D, is a thing you can do during readline #30790.

What is stdin stdout stderr?

In computer programming, standard streams are interconnected input and output communication channels between a computer program and its environment when it begins execution. The three input/output (I/O) connections are called standard input (stdin), standard output (stdout) and standard error (stderr).

Does every process have stdin?

Every process is initialized with three open file descriptors called stdin , stdout , and stderr .

How does stdin work in Linux?

stdin − It stands for standard input, and is used for taking text as an input. stdout − It stands for standard output, and is used to text output of any command you type in the terminal, and then that output is stored in the stdout stream. stderr − It stands for standard error.


2 Answers

If process a spawns process b, and process b spawns process c (so c is the grandchild of a), b can terminate and close its copy of the file descriptor that was its stdout (presumably, b's stdout is the write side of a pipe that a is watching.) But c still has that pipe open, so a will get the SIGCHLD from b, but will not get EOF on the pipe. In other words, yes, it can happen that the child terminates but the parent does not see the pipe close.

Also, it is a common coding error that a still has the write side of the pipe open. In that case, b can terminate and close its copy of the write side of the pipe, but the parent never sees the pipe close because the parent is keeping it open.

like image 175
William Pursell Avatar answered Sep 25 '22 23:09

William Pursell


All file descriptors are closed by the system at process exit. What can happen, is that there is some output stored in buffers, which has not been flushed.

If the child process never terminates, then it can happen, that your parent waits forever and never reaches waitpid().

Edit:

When your child terminates, all descriptors are closed and then you will finally get 0 on read() (or -1 if something went wrong!). So, you might want to change to:

...
if (n > 0) {
    // do something with output
} else if (n <= 0) {
    child_stdout = -1
}

Your code won't terminate though, because of:

if (n >= 0) {  // n > 0 || n == 0
    // ...
} else if (n == 0) {
    // Never reached!
}
like image 31
Olaf Dietsche Avatar answered Sep 25 '22 23:09

Olaf Dietsche