I'm a bit new to fifo
s on Linux and also have limited experience with select()
.
I've learned that calling open()
on the read-end of a FIFO will block until the write end completes the pipe.
One can open the read end of the fifo with O_NONBLOCK
in order to not block at open()
. You can then select()
with the fifo's file descriptor in the readfds in order to know when the file is openable - true?
What I'm confused by now, though: after knowing that the file is openable, I'd subsequently like to know that the fifo has readable contents, i.e. I'd like to know that read()
on the fifo file descriptor would not block. For this, I would have thought to select()
with the fifo file descriptor in the readfds - but this seems to conflict with using select()
to know if the file is openable.
So I guess to summarize my question: how can I use select()
to know 1) when open()
on the read end of a fifo would not block, and 2) when read()
on a fifo would not block?
My assumption that select()
unblocks on the read end to indicate that the fifo is openable appears to be incorrect. It looks like select()
unblocks on the read end only when there is data to read in the fifo.
This test code demonstrates my observation: as is, the select()
times out; uncomment the single commented line, and select()
unblocks on the fifo file descriptor.
#include <iostream>
#include <pthread.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/select.h>
#include <ctime>
#define FIFO "/tmp/foo"
void* sr1( void* arg )
{
mkfifo( FIFO, 0777 );
sleep( 3 );
int fd = open ( FIFO, O_WRONLY );
//write( fd, "a", 1 );
std::cout << "t1 opened " << fd << std::endl;
sleep( 3 );
close( fd );
std::cout << "t1 closed " << fd << std::endl;
return NULL;
}
void* sr2( void* arg )
{
int fd = open( FIFO, O_RDONLY | O_NONBLOCK );
std::cout << "t2 opened " << fd << std::endl;
fd_set readfds;
FD_ZERO( &readfds );
FD_SET( fd, &readfds );
struct timeval ts = { 5, 0 };
std::cout << "t2 waiting now" << std::endl;
select( fd + 1, &readfds, NULL, NULL, &ts );
if ( FD_ISSET( fd, &readfds ) )
{
std::cout << "t2 " << fd << " set so select() unblocked" << std::endl;
}
else
{
std::cout << "t2 " << " select() unblocked at timeout" << std::endl;
}
close( fd );
std::cout << "t2 closed " << fd << std::endl;
return NULL;
}
int main( int argc, char* argv[] )
{
pthread_t t1;
pthread_t t2;
pthread_create( &t1, NULL, sr1, NULL );
pthread_create( &t2, NULL, sr2, NULL );
pthread_join( t1, NULL );
pthread_join( t2, NULL );
}