Say we have a named pipe called fifo
, and we're reading and writing to it from two different shells. Consider these two examples:
shell 1$ echo foo > fifo
<hangs>
shell 2$ cat fifo
foo
shell 1$ echo bar > fifo
<hangs>
shell 1$ cat > fifo
<typing> foo
<hangs>
shell 2$ cat fifo
foo
^C
shell 1$
<typing> bar
<exits>
I can't wrap my head around what happens in these examples, and in particular why trying to write 'bar' to the pipe in the first example results in a blocking call, whereas in the second example it triggers a SIGPIPE.
I do understand that in the first case, two separate processes write to the pipe, and thus it is opened twice, while in the second case it is only opened once by a single process and written to twice, with the process reading from the pipe being killed in the meantime. What I don't understand is how that affects the behaviour of write
.
The pipe(7)
man page states:
If all file descriptors referring to the read end of a pipe have been closed, then a write(2) will cause a SIGPIPE signal to be generated for the calling process.
This condition doesn't sound clear to me. A closed file descriptor just ceases to be a file descriptor, right? How does saying "the reading end of the pipe has been closed" differ from "the reading end of the pipe is not open"?
I hope my question was clear enough. By the way, if you could suggest pointers for understanding in details the functioning of Unix pipes in relationship to open
, close
, read
and write
operations, I'd greatly appreciate it.
Best Answer
Your example is using a
fifo
not apipe
, so is subject tofifo(7)
.pipe(7)
also tells:So now from
fifo(7)
:So before both ends (here meaning there is at least a reader and a writer) are opened, write blocks as per
fifo(7)
. After both ends have been opened, and then (the) reading end(s) closed, write generates SIGPIPE as perpipe(7)
.For an example of pipe usage (not fifo) look at the example section of
pipe(2)
: involves pipe() (no open(), since pipe() actually created the pipe pair opened), close(), read() write() and fork() (there's almost always a fork() around when using a pipe).The simpliest way to handle SIGPIPE from your own C code if you don't want it to die when writing to a fifo, would be to call
signal(SIGPIPE, SIG_IGN);
and handle it by checking for errnoEPIPE
after each write() instead.