Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

using EOF for signaling on unnamed pipes

Tags:

People also ask

How do you send EOF to pipe?

EOF is not a character nor an "event" and could not be sent through the pipe, or "fed" to its writing end, as some stubborn urban legend suggests. The only way to generate an EOF on the reading end of a pipe/fifo (ie cause a read(2) on it to return 0) is to close all open handles to its writing end.

What is the difference between named and unnamed pipes?

An unnamed pipe is a direct connection between two commands running in the same terminal. If we want to send output from a command in one terminal to another command in a different terminal, we can use a named pipe, or FIFO. FIFO stands for first in, first out. This is a pipe that exists in the file system.

Does Echo Send EOF?

There is no way to echo out an EOF. An EOF can only be generated either by reaching the end of a file or by invoking the keypress bound to the eof terminal setting ( Ctrl D by default) when the file being read is bound to the terminal.


I have a test program that uses unnamed pipes created with pipe() to communicate between parent and child processes created with fork() on a Linux system.

Normally, when the sending process closes the write fd of the pipe, the receiving process returns from read() with a value of 0, indicating EOF.

However, it seems that if I stuff the pipe with a fairly large amount of data (maybe 100K bytes0 before the receiver starts reading, the receiver blocks after reading all the data in the pipe - even though the sender has closed it.

I have verified that the sending process has closed the pipe with lsof, and it seems pretty clear that the receiver is blocked.

Which leads to the question: is closing one end of the pipe a reliable way to let the receiver know that there is no more data?

If it is, and there are no conditions that can lead to a read() blocking on an empty, closed FIFO, there's something wrong with my code. If not, it means I need to find an alternate method of signalling the end of the data stream.

Resolution

I was pretty sure that the original assumption was correct, that closing a pipe causes an EOF at the reader side, this question was just a shot in the dark - thinking maybe there was some subtle pipe behavior I was overlooking. Nearly every example you ever see with pipes is a toy that sends a few bytes and exits. Things often work differently when you are no longer doing atomic operations.

In any case, I tried to simplify my code to flush out the problem and was successful in finding my problem. In pseudocode, I ended up doing something like this:

create pipe1
if ( !fork() ) {
    close pipe1 write fd
   do some stuff reading pipe1 until EOF
}
create pipe2
if ( !fork() )  {
   close pipe2 write fd
   do some stuff reading pipe2 until EOF
}
close pipe1 read fd
close pipe2 read fd
write data to pipe1
get completion response from child 1
close pipe1 write fd
write data to pipe2
get completion response from child 2
close pipe2 write fd
wait for children to exit

The child process reading pipe1 was hanging, but only when the amount of data in the pipe became substantial. This was occurring even though I had closed the pipe that child1 was reading.

A look at the source shows the problem. When I forked the second child process, it grabbed its own copy of the pipe1 file descriptors, which were left open. Even though only one process should be writing to the pipe, having it open in the second process kept it from going into an EOF state.

The problem didn't show up with small data sets, because child2 was finishing its business quickly, and exiting. But with larger data sets, child2 wasn't returning quickly, and I ended up with a deadlock.