diff --git a/ChangeLog b/ChangeLog index fc33a6d812382e80caca0d6ce8a7e36ce81d278d..8f6313bce837ce6aaa38de8644cabaa3927092fe 100644 --- a/ChangeLog +++ b/ChangeLog @@ -376,4 +376,5 @@ * Correct bug in recursive mutex logic * Add mkfifo() * Add pipe() and test for both pipes and fifos + * Attempts to open a FIFO will now block until there is at least one writer diff --git a/Documentation/NuttX.html b/Documentation/NuttX.html index 70b781c8ede2f77943d5f68cae63a5b1c6e2dc4f..5d3c130bcd6dfed5bf40de88608dd3e58b7bf893 100644 --- a/Documentation/NuttX.html +++ b/Documentation/NuttX.html @@ -1025,6 +1025,7 @@ nuttx-0.3.12 2008-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr> * Correct bug in recursive mutex logic * Add mkfifo() * Add pipe() and test for both pipes and fifos + * Attempts to open a FIFO will now block until there is at least one writer pascal-0.1.3 2008-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr> diff --git a/drivers/fifo.c b/drivers/fifo.c index 88ab1deb60f61fdbeb465cd29390eed750876f1f..9ad64dbcb2ebf25aba2f450a49c44a61b4fbfbfa 100644 --- a/drivers/fifo.c +++ b/drivers/fifo.c @@ -96,8 +96,12 @@ static struct file_operations fifo_fops = * Once the FIFO has been created by mkfifo(), any thread can open it for * reading or writing, in the same way as an ordinary file. However, it must * have been opened from both reading and writing before input or output - * can be performed. Unlike other mkfifo() implementations, this one will - * NOT block when the FIFO is opened on only one end. + * can be performed. This FIFO implementation will block all attempts to + * open a FIFO read-only until at least one thread has opened the FIFO for + * writing. + * + * If all threads that write to the FIFO have closed, subsequent calls to + * read() on the FIFO will return 0 (end-of-file). * * Inputs: * pathname - The full path to the FIFO instance to attach to or to create diff --git a/drivers/pipe-common.c b/drivers/pipe-common.c index 1004d15f876d767eb133f82e17dea389e8783683..ab6b7d3808ca91f1da8afb7c03b814e554d1e831 100644 --- a/drivers/pipe-common.c +++ b/drivers/pipe-common.c @@ -139,6 +139,7 @@ int pipecommon_open(FAR struct file *filep) { struct inode *inode = filep->f_inode; struct pipe_dev_s *dev = inode->i_private; + int sval; /* Some sanity checking */ #if CONFIG_DEBUG @@ -160,11 +161,37 @@ int pipecommon_open(FAR struct file *filep) if ((filep->f_oflags & O_WROK) != 0) { dev->s.d_nwriters++; + + /* If this this is the first writer, then the read semaphore indicates the + * number of readers waiting for the first writer. Wake them all up. + */ + if (dev->s.d_nwriters == 1) + { + while (sem_getvalue(&dev->s.d_rdsem, &sval) == 0 && sval < 0) + { + sem_post(&dev->s.d_rdsem); + } + } } /* If opened for read-only, then wait for at least one writer on the pipe */ + sched_lock(); (void)sem_post(&dev->s.d_bfsem); + if ((filep->f_oflags & O_RDWR) != O_RDONLY && dev->s.d_nwriters < 1) + { + /* NOTE: d_rdsem is normally used when the read logic waits for more + * data to be written. But until the first writer has opened the + * pipe, the meaning is different: it is used prevent O_RDONLY open + * calls from returning until there is at least one writer on the pipe. + * This is required both by spec and also because it prevents + * subsequent read() calls from returning end-of-file because there is + * no writer on the pipe. + */ + + pipecommon_semtake(&dev->s.d_rdsem); + } + sched_unlock(); return OK; } return ERROR; diff --git a/examples/pipe/pipe_main.c b/examples/pipe/pipe_main.c index 5b3874171454fb022a0d108e98e8d3b20c8abe5a..eadad056292a264cfe749ad657e4ba189a1d101f 100644 --- a/examples/pipe/pipe_main.c +++ b/examples/pipe/pipe_main.c @@ -127,7 +127,7 @@ static void *reader(pthread_addr_t pvarg) if (nbytes > NREAD_BYTES) { fprintf(stderr, "reader: Too many bytes read -- aborting: %d\n", nbytes); - return (void*)3; + return (void*)4; } } printf("reader: %d bytes read\n", nbytes);