Search code examples
clinuxposixnamed-pipesfifo

POSIX FIFO freezes when opened in blocking mode


By default a POSIX FIFO is opened in blocking mode. My problem is that when I open it in blocking mode it just freezes (blocks) and nothing else happens.

Originally I opened both sides with the RDWR flag and I had no problems because RDWR makes it nonblocking because "Under Linux, opening a FIFO for read and write will succeed both in blocking and nonblocking mode" (https://linux.die.net/man/7/fifo). But in nonblocking mode I sometimes get dropped records, so I need to open it in blocking mode.

Here's how I call mkfifo:

int64_t fifo_setup(char * fifo_name)
{
    if (mkfifo(fifo_name, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH) == -1) {
        perror("mkfifo");
        exit(EXIT_FAILURE); }

   return 0; }

My original call to open:

int64_t fifo_open(char * fifo_name, int64_t read_write) {

    int c;

    if (read_write == 1) { 
        c = open(fifo_name, O_RDWR);}
    if (read_write == 2) { 
        c = open(fifo_name, O_RDWR);}

    perror("open");

    return (c);
}

Then I changed it to:

int64_t fifo_open(char * fifo_name, int64_t read_write) {

    int c;

    if (read_write == 1) { 
        c = open(fifo_name, O_WRONLY);}
    if (read_write == 2) { 
        c = open(fifo_name, O_RDONLY);}

    perror("open");

    return (c);
}

My program reaches the open call for the writer threads (this is a NASM call to C):

Open_FIFO_Write:
lea rdi,[fifo_name]
mov rsi,1
call fifo_open wrt ..plt
mov [fifo_write_fd],rax

But then the Putty terminal freezes (blocks) and nothing else happens. I never get to the block that opens the reading side. Specifically it blocks just before it reaches perror("open") in the fifo_open code above:

According to the Linux man page at https://www.man7.org/linux/man-pages/man7/fifo.7.html, "Normally, opening the FIFO blocks until the other end is opened also." That's great but I can't get to the code that opens the writer because the reader blocks all further progress. It's like a Mexican standoff.

Of course there must be a way but my research hasn't found it yet.

Thanks for any help on this.


Solution

  • Three options:

    1. FIFOs themselves don't drop messages in nonblocking mode. If your code is dropping messages, fix your code to stop doing that, and then just use nonblocking mode.
    2. Open the FIFO in nonblocking mode, then once you get both ends open, use fcntl to change it to blocking mode.
    3. Use a separate thread or process to open each half of the FIFO.