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
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).
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.
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.
Yes, multiple processes can read from (or write to) a pipe. But data isn't duplicated for the processes.
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.
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.
If there is already a reader the open
will immediately return successfully.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With