From 28db0e083a7dc3b9b87813e4273b68c7111be15b Mon Sep 17 00:00:00 2001 From: patacongo Date: Sat, 26 Jul 2008 14:24:17 +0000 Subject: [PATCH] O_RDONLY open on FIFO blocks until writer opens git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@781 42af7a65-404d-4744-a932-0658087f49c3 --- ChangeLog | 1 + Documentation/NuttX.html | 1 + drivers/fifo.c | 8 ++++++-- drivers/pipe-common.c | 27 +++++++++++++++++++++++++++ examples/pipe/pipe_main.c | 2 +- 5 files changed, 36 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index fc33a6d812..8f6313bce8 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 70b781c8ed..5d3c130bcd 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 88ab1deb60..9ad64dbcb2 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 1004d15f87..ab6b7d3808 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 5b38741714..eadad05629 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);