Is closing a pipe necessary when followed by execl

2019-08-12 14:52发布

Before stating my question, I have read several related questions on stack overflow, such as pipe & dup functions in UNIX, and several others,but didn't clarify my confusion.

First, the code, which is an example code from 'Beginning Linux Programming', 4th edition, Chapter 13:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main()
{
int data_processed;
int file_pipes[2];
const char some_data[] = "123";
pid_t fork_result;

if (pipe(file_pipes) == 0)
   {
    fork_result = fork();
    if (fork_result == (pid_t)-1)
       {
        fprintf(stderr, "Fork failure");
        exit(EXIT_FAILURE);
       }

    if (fork_result == (pid_t)0)  // Child process
       {
        close(0);
        dup(file_pipes[0]);
        close(file_pipes[0]);   // LINE A
        close(file_pipes[1]);   // LINE B

        execlp("od", "od", "-c", (char *)0);
        exit(EXIT_FAILURE);
       }
    else    // parent process
       {
        close(file_pipes[0]);   // LINE C
        data_processed = write(file_pipes[1], some_data,
                               strlen(some_data));
        close(file_pipes[1]);   // LINE D
        printf("%d - wrote %d bytes\n", (int)getpid(), data_processed);
       }
   }
exit(EXIT_SUCCESS);
}

The execution result is:

momo@xue5:~/TestCode/IPC_Pipe$ ./a.out

10187 - wrote 3 bytes

momo@xue5:~/TestCode/IPC_Pipe$ 0000000 1 2 3

0000003

momo@xue5:~/TestCode/IPC_Pipe$

If you commented LINE A, LINE C, and LINE D, the result is the same as above. I understand the result, the child get the data from its parent through its own stdin which is connected to pipe, and send 'od -c' result to its stdout.

However, if you commented LINE B, the result would be:

momo@xue5:~/TestCode/IPC_Pipe$ ./a.out

10436 - wrote 3 bytes

momo@xue5:~/TestCode/IPC_Pipe$

No 'od -c' result! Is 'od -c' started by execlp() not excuted, or its output not directed to stdout? One possibility is the read() of 'od' is blocked, because the write file descriptor file_pipes[1] of child is open if you commented LINE B. But commenting LINE D, which let write file descriptor file_pipes[1] of parent open, can still have the 'od -c' output.

And, why we need to close pipe before execlp()? execlp() will replace the process image, including stack, .data, .heap, .text with new image from 'od'. Does that mean, even if you don't close file_pipes[0] and file_pipes[1] in child as LINE A and B, file_pipes[0] and file_pipes[1] will still be 'destroyed' by execlp()? From the result by code, it is not. But where am I wrong?

Thanks so much for your time and efforts here~~

标签: c pipe dup
2条回答
该账号已被封号
2楼-- · 2019-08-12 15:26

And, why we need to close pipe before execlp()? execlp() will replace the process image, including stack, .data, .heap, .text with new image from 'od'.

Yes, the exec-family functions, including execlp(), replace the process image of the calling process with a copy of the specified program. But the process's table of open file descriptors is not part of the process image -- it is maintained by the kernel, and it survives the exec.

Does that mean, even if you don't close file_pipes[0] and file_pipes[1] in child as LINE A and B, file_pipes[0] and file_pipes[1] will still be 'destroyed' by execlp()?

The variable file_pipes is destroyed by execlp(), but that's just the program's internal storage for the file descriptors. The descriptors are just integer indexes into a table maintained for the process by the kernel. Losing track of the file descriptor values does not cause the associated files to be closed. In fact, that's a form of resource leakage.

From the result by code, it is not. But where am I wrong?

As described above.

Additionally, when a process exits, all its open file descriptors are closed, but the underlying open file description in the kernel, to which the file descriptors refer, is closed only when no open file descriptors referring to it remain. Additional open file descriptors may be held by other processes, as a result of inheriting them across a fork().

Now as to the specific question of what happens when the child process does not close file_pipes[1] before execing od, you might get a clue by checking the process list via the ps command. You will see the child od process still running (maybe several, if you have tested several times). Why?

Well, how does od know when to exit? It processes its entire input, so it must exit when it reaches the end of its input(s). But the end of input on a pipe doesn't mean that no more data is available right now, because more data might later be written to the write end of the pipe. End of input on a pipe happens when the write end is closed. And if the child does not close file_pipes[1] before it execs, then it likely will remain open indefinitely, because after the exec the child doesn't any longer know that it owns it.

查看更多
你好瞎i
3楼-- · 2019-08-12 15:29

Is closing a pipe necessary when followed by execlp()?

It's not strictly necessary because it depends on how the pipe is used. But in general, yes it should be closed if the pipe end is not needed by the process.

why we need to close pipe before execlp()? execlp() will replace the process image

Because file descriptors (by default) remain open across exec calls. From the man page: "By default, file descriptors remain open across an execve(). File descriptors that are marked close-on-exec are closed; see the description of FD_CLOEXEC in fcntl(2)."

However, if you commented LINE B,...No 'od -c' result!

This is because the od process reads from stdin until it gets an EOF. If the process itself does not close file_pipes[1] then it will not see an EOF as the write end of the pipe would not be fully closed by all processes that had it opened.

If you commented LINE A, LINE C, and LINE D, he result is the same as above

This is because the file descriptors at A and C are read ends of the pipe and no one will be blocked waiting for it to be closed (as described above). The file descriptor at D is a write end and not closing it would indeed cause problems. However, even though the code does not explicitly call close on that file descriptor, it will still be closed because the process exits.

查看更多
登录 后发表回答