Alex Rose
Alex Rose

Reputation: 127

Linux fifo (named pipe) O_NONBLOCK breaks pipe

I've been writing a small program in C++ for linux using inter process communication. I had a problem when trying to read in a non-blocking way with one process and write (blocking) with another process. The issue looks like this, when the parent tries to read the pipe with O_NONBLOCK (or O_NDELAY) it never reads a single byte and when the child tries to write on the pipe, it fails and the SIGPIPE broken pipe signal is sent. Here is an example of the code:

// Parent process
mkfifo(PROC_COPROC, 0666);

int fd_co = open(PROC_COPROC, O_RDONLY | O_NDELAY);
char c;
int n;
fcntl(fd_co,F_SETFL,0); //fix it
while ((n = read(fd_co, &c, 1)) > 0)
{
    printf("%c", c);
}
close(fd_co);

// Child process
int fd = open(PROC_COPROC, O_WRONLY | O_APPEND);
if ( fd != -1 ) 
{
    write( fd , "message\n" , 8); //Fails here if flag not set
}
else
    printf("Ne peut pas ecrire sur le fifo\n");
close(fd);

I finally found a way to resolve this by using fcntl(fd_co,F_SETFL,0); right after the non-blocking open call.

After reading the man page, I couldn't find any (simple) explanation why I sould reset the file descriptor's flag if I want to read non-blocking and write blocking.

Anyone has an explanation or am I doing it wrong?

Upvotes: 0

Views: 7423

Answers (1)

Olaf Dietsche
Olaf Dietsche

Reputation: 74018

The "problem" with O_NDELAY is, that read returns -1 and sets errno to EAGAIN, when there's no data available. So, you must test the return value of read for -1 and errno and then read again.

Your "fix" just resets O_NDELAY, which makes read block again, if there's nothing to read from the FIFO.

See also read

RETURN VALUE
... On error, -1 is returned, and errno is set appropriately.

ERRORS
EAGAIN The file descriptor fd refers to a file other than a socket and has been marked nonblocking (O_NONBLOCK), and the read would block.
EAGAIN or EWOULDBLOCK
The file descriptor fd refers to a socket and has been marked nonblocking (O_NONBLOCK), and the read would block. POSIX.1-2001 allows either error to be returned for this case, and does not require these constants to have the same value, so a portable application should check for both possibilities.

You might also consider using select, or poll as @BasileStarynkevitch suggested, if blocking is a problem in your case.

Upvotes: 4

Related Questions