Download Introduction to Operating Systems Abstractions Using Plan 9 from

Transcript
- 114 consumes what may still be going through the pipe. This is the output for the program.
; 8.pipeto
; warning: the world is over
warning: it was not true
Because the parent process finishes before the child is still processing the input that comes from
the pipe, the shell prompt gets printed almost immediately. If this is a problem, the parent must
wait for the child after writing all the data to the pipe. Otherwise, the waitpid call would block
waiting for the child to die, and the child would block waiting for the end of file indication
(because the parent has the pipe open for writing).
Figure 5.3 shows the processes involved, all their descriptors, and the pipe. We use the
same conventions used for the last figure, which we will follow from now on.
2
0
Parent
Process
1
2
fd
pipe
0
grep
1
Figure 5.3: A process using a pipe to send input to a command.
All the interesting things happen in the function pipeto. It executes the Plan 9 shell, suppling the command line as the argument for option -c, this asks rc to execute the argument as a
command, and not to read commands from standard input.
First, before creating the child process, the parent process makes a pipe. It is very important
to understand that the pipe must be created before we call fork. Both processes must share the
pipe. If the pipe is created after forking, in the child process, the parent process does not have the
descriptor to write to the pipe. If it is created by the parent, after calling fork, the child will not
have the descriptor to read from the pipe.
Even if both processes create a pipe, after the child creation, there are two different pipes.
Each process can use only its own pipe, but they cannot talk. It does not matter if the numbers
returned from pipe for the two descriptors are the same (or not) for both processes: They are different descriptors because each process made its own call to pipe. Therefore, pipes are created
always by a common ancestor of the processes communicating through the pipe.
Another important detail is that all the descriptors are closed (by all processes) as soon as
they are no longer useful. The child is going to call execl, and the new program will read from
its standard input. Thus, the child must close both pipe descriptors after redirecting its standard
input to the end for reading from the pipe. The parent process is going to write to the pipe, but it
is not going to read. It closes the end for reading from the pipe. Not doing so risks leaving open
the pipe for writing, and in this case the reader process would never get its end of file indication.
Why does the child redirect its standard input to the pipe and not the parent? We wrote the
code for the parent. We know that it has fd[1] open for writing, and can just use that descriptor
for writing. On the other hand, the child does not know! After the child executes grep, how can
grep possibly know that it should use a file descriptor other than zero for reading?
The following example is a counterpart to what we made. This function creates a child process that is used to execute a command. However, this time, we return the output produced by the