Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to determine if pipe can be written

Is there a way (in C, or preferably in Perl) to determine whether a named pipe may be written - i.e. there is an active reading process It seems that if I open for write nonblocking, the open returns at once but a select for write also returns immediately. The goal is for the writing process to just carry on (i.e. skip sending) if the reading end is not ready

like image 883
user1938139 Avatar asked Dec 19 '13 16:12

user1938139


People also ask

How much data can be written to pipe?

Since Linux 2.6. 11, the pipe capacity is 16 pages (i.e., 65,536 bytes in a system with a page size of 4096 bytes).

Does writing to a pipe block?

It does not receive an end of file (EOF) value, like when reading from a file. When a process tries to write to a named pipe that has no reader (e.g. the reader process has just closed the named pipe), the writing process gets blocked, until a second process re-opens the named pipe.

How do you know if FIFO is empty?

When a user process attempts to read from an empty pipe (or FIFO), the following happens: If one end of the pipe is closed, 0 is returned, indicating the end of the file. If the write side of the FIFO has closed, read(2) returns 0 to indicate the end of the file.

Can more than 1 process write on pipe at a time?

Yes, multiple processes can read from (or write to) a pipe. But data isn't duplicated for the processes.


2 Answers

Opening the write side of a pipe will block until a reader opens the read side, regardless of any other settings. So you can't return from open until the pipe is connected.

If a reader closes its side of an already open pipe, the writer will receive E_PIPE at the next write attempt. As far as I've been able to determine, this is the only indication you get that a pipe is no longer connected.

like image 192
Jim Garrison Avatar answered Oct 18 '22 18:10

Jim Garrison


Chances are that you are not paying attention to the return codes from open. If you open a FIFO for writing and as non-blocking there are two possible outcomes.

  1. If there is already a reader the open will immediately return successfully.

  2. If there is no pipe reader the open will fail with errno = ENXIO.

The following program demonstrates.

#include<stdio.h>
#include<unistd.h>
#include<errno.h>
#include<fcntl.h>
#include<stdlib.h>
#include <sys/stat.h>

#define SERVFIFO "/tmp/server.fifo"
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)

void syserr(const char *str)
{
    perror(str);
    exit(1);
}

int main(int argc, char** argv)
{
    umask(0);

    if (mkfifo(SERVFIFO, FILE_MODE) < 0 && errno != EEXIST)
        syserr("mkfifo");

    // try to open for write with no readers

    int fdw = open(SERVFIFO, O_WRONLY | O_NONBLOCK);
    if (fdw == -1)
        perror("non-blocking open for write with no readers failed");

    // create a reader - the process itself - non-blocking

    int fdr = open(SERVFIFO, O_RDONLY | O_NONBLOCK);
    if (fdr == -1)
        syserr("non-blocking open for read no writers failed");

    // try again to open for write but this time with a reader
    fdw = open(SERVFIFO, O_WRONLY | O_NONBLOCK);
    if (fdw == -1)
        syserr("non-blocking open with readers failed");

    printf("non-blocking open for write succeeded\n");

    close(fdw);
    close(fdr);
    unlink(SERVFIFO);
}

That said, the fact that the open fails without blocking isn't all that useful. About the only thing you can do is continually try to open until you succeed and that kind of polling can be wasteful, and in the context of a long running program waiting for intermittent readers is sort of ridiculous.

One solution is that used above - open the FIFO for reading yourself - but this has its own problems.

  1. If you use your FIFO write fd in your select statement it is always going to be writable...until it isn't. That is, because you are your own reader too, the FIFO writes will succeed until you fill the FIFO buffer with PIPE_BUF bytes. After that the FIFO won't be writable and your writes will fail with EAGAIN until a legitimate reader (i.e. not yourself) comes along, opens for reading, and starts draining the buffer.

  2. By opening your own FIFO for reading and writing, you won't see an EOF from legitimate users when they close the FIFO. Since you are only concerned about writing this may not be an issue for you.

Another possible solution, which I have never tried, is to use inotify on your FIFO. You can monitor the inotify file descriptor in your select and determine when someone has opened the FIFO. Then you know you can safely open your end for writing. You would probably want to mask off open permissions on the FIFO so that you can be the only writer, if possible for your application.

FIFOs should be renamed PITAs for these funky semantics. If you can make the change, this is why the Unix gods bestowed domain sockets upon us mere mortals.

like image 29
Duck Avatar answered Oct 18 '22 18:10

Duck