Why does my program hang when opening a mkfifo-ed pipe?
Solution 1:
Try passing "w"
as the mode to fopen. "rw"
is not a valid mode argument for fopen
, and even if it was, you probably don't want to both read and write to the FIFO in the same process (although it is possible, see below).
As an aside, the correct mode argument for opening a file for both reading and writing is either "r+"
or "w+"
(see the answers to this question for the differences).
This program will correctly write to the FIFO:
#include <stdio.h>
int main(int argc, char** argv) {
FILE* fp = fopen("/tmp/myFIFO", "w");
fprintf(fp, "Hello, world!\n");
fclose(fp);
return 0;
}
Note that fopen
in the above program will block until the FIFO is opened for reading. When it blocks, run this in another terminal:
$ cat /tmp/myFIFO
Hello, world!
$
The reason why it blocks is because fopen
does not pass O_NONBLOCK
to open
:
$ strace -P /tmp/myFIFO ./a.out
open("/tmp/myFIFO", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
...
Some background on how FIFOs are opened
Read-only, without O_NONBLOCK
: open
blocks until another process opens the FIFO for writing. This is the behavior when using fopen
with mode argument "r"
.
Write-only, without O_NONBLOCK
: open
blocks until another process opens the FIFO for reading. This is the behavior when using fopen
with mode argument "w"
.
Read-only, with O_NONBLOCK
: open
returns immediately.
Write-only, with O_NONBLOCK
: open
returns an error with errno
set to ENXIO
unless another process has the FIFO open for reading.
Info from "Advanced Programming in the UNIX Environment" by W. Richard Stevens.
Opening a FIFO for read and write
Opening a FIFO for reading and writing within the same process is also possible with Linux. The Linux FIFO man page states:
Under Linux, opening a FIFO for read and write will succeed both in blocking and nonblocking mode. POSIX leaves this behavior undefined. This can be used to open a FIFO for writing while there are no readers available. A process that uses both ends of the connection in order to communicate with itself should be very careful to avoid deadlocks.
Here's a program which writes to and reads from the same FIFO:
#include <stdio.h>
int main(int argc, const char *argv[]) {
char buf[100] = {0};
FILE* fp = fopen("/tmp/myFIFO", "r+");
fprintf(fp, "Hello, world!\n");
fgets(buf, sizeof(buf), fp);
printf("%s", buf);
fclose(fp);
return 0;
}
It does not block, and returns immediately:
$ gcc fifo.c && ./a.out
Hello, world!
Note that this is not portable and may not work on operating systems besides Linux.
Solution 2:
The process blocks until the other end of the pipe gets opened.