Why does my program hang when opening a mkfifo-ed pipe?

flyingbin picture flyingbin · Dec 14, 2011 · Viewed 14.5k times · Source

I use mkfifo to create a named pipe. Then I use the following program to open it. However, the program hangs at the line "fopen". Is there something wrong here?

int main(int argc, char** argv) {
char* line = "hello, world!";
FILE* fp = fopen("/tmp/myFIFO", "rw");
fprintf(fp, line);
fclose(fp);
return 0;
}

Answer

Tim picture Tim · Jul 24, 2012

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.