summaryrefslogtreecommitdiff
path: root/nuttx/drivers/pipes
diff options
context:
space:
mode:
Diffstat (limited to 'nuttx/drivers/pipes')
-rw-r--r--nuttx/drivers/pipes/Make.defs41
-rw-r--r--nuttx/drivers/pipes/fifo.c139
-rw-r--r--nuttx/drivers/pipes/pipe.c282
-rw-r--r--nuttx/drivers/pipes/pipe_common.c654
-rw-r--r--nuttx/drivers/pipes/pipe_common.h136
5 files changed, 1252 insertions, 0 deletions
diff --git a/nuttx/drivers/pipes/Make.defs b/nuttx/drivers/pipes/Make.defs
new file mode 100644
index 000000000..be16366bb
--- /dev/null
+++ b/nuttx/drivers/pipes/Make.defs
@@ -0,0 +1,41 @@
+############################################################################
+# drivers/pipes/Make.defs
+#
+# Copyright (C) 2009 Gregory Nutt. All rights reserved.
+# Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# 3. Neither the name NuttX nor the names of its contributors may be
+# used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+############################################################################
+
+PIPE_ASRCS =
+ifneq ($(CONFIG_NFILE_DESCRIPTORS),0)
+PIPE_CSRCS = pipe.c fifo.c pipe_common.c
+else
+PIPE_CSRCS =
+endif
diff --git a/nuttx/drivers/pipes/fifo.c b/nuttx/drivers/pipes/fifo.c
new file mode 100644
index 000000000..bc9f629f5
--- /dev/null
+++ b/nuttx/drivers/pipes/fifo.c
@@ -0,0 +1,139 @@
+/****************************************************************************
+ * drivers/pipes/fifo.c
+ *
+ * Copyright (C) 2008-2009 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Compilation Switches
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/types.h>
+#include <nuttx/fs.h>
+#include <errno.h>
+
+#include "pipe_common.h"
+
+#if CONFIG_DEV_PIPE_SIZE > 0
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct file_operations fifo_fops =
+{
+ pipecommon_open, /* open */
+ pipecommon_close, /* close */
+ pipecommon_read, /* read */
+ pipecommon_write, /* write */
+ 0, /* seek */
+ 0 /* ioctl */
+#ifndef CONFIG_DISABLE_POLL
+ , pipecommon_poll /* poll */
+#endif
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: mkfifo
+ *
+ * Description:
+ * mkfifo() makes a FIFO device driver file with name 'pathname.' Unlike
+ * Linux, a NuttX FIFO is not a special file type but simply a device driver
+ * instance. 'mode' specifies the FIFO's permissions.
+ *
+ * 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. 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
+ * (if not already created).
+ * mode - Ignored for now
+ *
+ * Return:
+ * 0 is returned on success; otherwise, -1 is returned with errno set
+ * appropriately.
+ *
+ ****************************************************************************/
+int mkfifo(FAR const char *pathname, mode_t mode)
+{
+ struct pipe_dev_s *dev;
+ int ret;
+
+ /* Allocate and initialize a new device structure instance */
+
+ dev = pipecommon_allocdev();
+ if (!dev)
+ {
+ return -ENOMEM;
+ }
+
+ ret = register_driver(pathname, &fifo_fops, mode, (void*)dev);
+ if (ret != 0)
+ {
+ pipecommon_freedev(dev);
+ }
+ return ret;
+}
+#endif /* CONFIG_DEV_PIPE_SIZE > 0 */
diff --git a/nuttx/drivers/pipes/pipe.c b/nuttx/drivers/pipes/pipe.c
new file mode 100644
index 000000000..95049b354
--- /dev/null
+++ b/nuttx/drivers/pipes/pipe.c
@@ -0,0 +1,282 @@
+/****************************************************************************
+ * drivers/pipes/pipe.c
+ *
+ * Copyright (C) 2008-2009 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Compilation Switches
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/types.h>
+#include <nuttx/fs.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <semaphore.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "pipe_common.h"
+
+#if CONFIG_DEV_PIPE_SIZE > 0
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+
+#define MAX_PIPES 32
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int pipe_close(FAR struct file *filep);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct file_operations pipe_fops =
+{
+ pipecommon_open, /* open */
+ pipe_close, /* close */
+ pipecommon_read, /* read */
+ pipecommon_write, /* write */
+ 0, /* seek */
+ 0 /* ioctl */
+#ifndef CONFIG_DISABLE_POLL
+ , pipecommon_poll /* poll */
+#endif
+};
+
+static sem_t g_pipesem = { 1 };
+static uint32 g_pipeset = 0;
+static uint32 g_pipecreated = 0;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: pipe_allocate
+ ****************************************************************************/
+
+static inline int pipe_allocate(void)
+{
+ int pipeno;
+ int ret = -ENFILE;
+
+ for (pipeno = 0; pipeno < MAX_PIPES; pipeno++)
+ {
+ if ((g_pipeset & (1 << pipeno)) == 0)
+ {
+ g_pipeset |= (1 << pipeno);
+ ret = pipeno;
+ break;
+ }
+ }
+ return ret;
+}
+
+/****************************************************************************
+ * Name: pipe_free
+ ****************************************************************************/
+
+static inline void pipe_free(int pipeno)
+{
+ int ret = sem_wait(&g_pipesem);
+ if (ret == 0)
+ {
+ g_pipeset &= ~(1 << pipeno);
+ (void)sem_post(&g_pipesem);
+ }
+}
+
+/****************************************************************************
+ * Name: pipe_close
+ ****************************************************************************/
+
+static int pipe_close(FAR struct file *filep)
+{
+ struct inode *inode = filep->f_inode;
+ struct pipe_dev_s *dev = inode->i_private;
+ int ret;
+
+ /* Some sanity checking */
+#if CONFIG_DEBUG
+ if (!dev)
+ {
+ return -EBADF;
+ }
+#endif
+
+ /* Perform common close operations */
+
+ ret = pipecommon_close(filep);
+ if (ret == 0 && dev->d_refs == 0)
+ {
+ /* Release the pipe when there are no further open references to it. */
+
+ pipe_free(dev->d_pipeno);
+ }
+ return ret;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: pipe
+ *
+ * Description:
+ * pipe() creates a pair of file descriptors, pointing to a pipe inode, and
+ * places them in the array pointed to by 'filedes'. filedes[0] is for reading,
+ * filedes[1] is for writing.
+ *
+ * Inputs:
+ * filedes[2] - The user provided array in which to catch the pipe file
+ * descriptors
+ *
+ * Return:
+ * 0 is returned on success; otherwise, -1 is returned with errno set
+ * appropriately.
+ *
+ ****************************************************************************/
+
+int pipe(int filedes[2])
+{
+ struct pipe_dev_s *dev = NULL;
+ char devname[16];
+ int pipeno;
+ int err;
+ int ret;
+
+ /* Get exclusive access to the pipe allocation data */
+
+ ret = sem_wait(&g_pipesem);
+ if (ret < 0)
+ {
+ /* sem_wait() will have already set errno */
+
+ return ERROR;
+ }
+
+ /* Allocate a minor number for the pipe device */
+
+ pipeno = pipe_allocate();
+ if (pipeno < 0)
+ {
+ (void)sem_post(&g_pipesem);
+ err = -pipeno;
+ goto errout;
+ }
+
+ /* Create a pathname to the pipe device */
+
+ sprintf(devname, "/dev/pipe%d", pipeno);
+
+ /* Check if the pipe device has already been created */
+
+ if ((g_pipecreated & (1 << pipeno)) == 0)
+ {
+ /* No.. Allocate and initialize a new device structure instance */
+
+ dev = pipecommon_allocdev();
+ if (!dev)
+ {
+ (void)sem_post(&g_pipesem);
+ err = ENOMEM;
+ goto errout_with_pipe;
+ }
+ dev->d_pipeno = pipeno;
+
+ /* Register the pipe device */
+
+ ret = register_driver(devname, &pipe_fops, 0666, (void*)dev);
+ if (ret != 0)
+ {
+ (void)sem_post(&g_pipesem);
+ err = -ret;
+ goto errout_with_dev;
+ }
+
+ /* Remember that we created this device */
+
+ g_pipecreated |= (1 << pipeno);
+ }
+ (void)sem_post(&g_pipesem);
+
+ /* Get a write file descriptor */
+
+ filedes[1] = open(devname, O_WRONLY);
+ if (filedes[1] < 0)
+ {
+ err = -filedes[1];
+ goto errout_with_driver;
+ }
+
+ /* Get a read file descriptor */
+
+ filedes[0] = open(devname, O_RDONLY);
+ if (filedes[0] < 0)
+ {
+ err = -filedes[0];
+ goto errout_with_wrfd;
+ }
+
+ return OK;
+
+errout_with_wrfd:
+ close(filedes[1]);
+errout_with_driver:
+ unregister_driver(devname);
+errout_with_dev:
+ pipecommon_freedev(dev);
+errout_with_pipe:
+ pipe_free(pipeno);
+errout:
+ errno = err;
+ return ERROR;
+}
+
+#endif /* CONFIG_DEV_PIPE_SIZE > 0 */
diff --git a/nuttx/drivers/pipes/pipe_common.c b/nuttx/drivers/pipes/pipe_common.c
new file mode 100644
index 000000000..60d028c00
--- /dev/null
+++ b/nuttx/drivers/pipes/pipe_common.c
@@ -0,0 +1,654 @@
+/****************************************************************************
+ * drivers/pipes/pipe_common.c
+ *
+ * Copyright (C) 2008-2009 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <sys/types.h>
+
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sched.h>
+#include <semaphore.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <assert.h>
+#include <debug.h>
+
+#include <nuttx/fs.h>
+#if CONFIG_DEBUG
+# include <nuttx/arch.h>
+#endif
+
+#include "pipe_common.h"
+
+#if CONFIG_DEV_PIPE_SIZE > 0
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* CONFIG_DEV_PIPEDUMP will dump the contents of each transfer into and out
+ * of the pipe.
+ */
+
+#ifdef CONFIG_DEV_PIPEDUMP
+# define pipe_dumpbuffer(m,a,n) lib_dumpbuffer(m,a,n)
+#else
+# define pipe_dumpbuffer(m,a,n)
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static void pipecommon_semtake(sem_t *sem);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: pipecommon_semtake
+ ****************************************************************************/
+
+static void pipecommon_semtake(sem_t *sem)
+{
+ while (sem_wait(sem) != 0)
+ {
+ /* The only case that an error should occur here is if the wait was
+ * awakened by a signal.
+ */
+
+ ASSERT(errno == EINTR);
+ }
+}
+
+/****************************************************************************
+ * Name: pipecommon_pollnotify
+ ****************************************************************************/
+
+#ifndef CONFIG_DISABLE_POLL
+static void pipecommon_pollnotify(FAR struct pipe_dev_s *dev, pollevent_t eventset)
+{
+ int i;
+
+ for (i = 0; i < CONFIG_DEV_PIPE_NPOLLWAITERS; i++)
+ {
+ struct pollfd *fds = dev->d_fds[i];
+ if (fds)
+ {
+ fds->revents |= (fds->events & eventset);
+ if (fds->revents != 0)
+ {
+ fvdbg("Report events: %02x\n", fds->revents);
+ sem_post(fds->sem);
+ }
+ }
+ }
+}
+#else
+# define pipecommon_pollnotify(dev,event)
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: pipecommon_allocdev
+ ****************************************************************************/
+
+FAR struct pipe_dev_s *pipecommon_allocdev(void)
+{
+ struct pipe_dev_s *dev;
+
+ /* Allocate a private structure to manage the pipe */
+
+ dev = (struct pipe_dev_s *)malloc(sizeof(struct pipe_dev_s));
+ if (dev)
+ {
+ /* Initialize the private structure */
+
+ memset(dev, 0, sizeof(struct pipe_dev_s));
+ sem_init(&dev->d_bfsem, 0, 1);
+ sem_init(&dev->d_rdsem, 0, 0);
+ sem_init(&dev->d_wrsem, 0, 0);
+ }
+ return dev;
+}
+
+/****************************************************************************
+ * Name: pipecommon_freedev
+ ****************************************************************************/
+
+void pipecommon_freedev(FAR struct pipe_dev_s *dev)
+{
+ sem_destroy(&dev->d_bfsem);
+ sem_destroy(&dev->d_rdsem);
+ sem_destroy(&dev->d_wrsem);
+ free(dev);
+}
+
+/****************************************************************************
+ * Name: pipecommon_open
+ ****************************************************************************/
+
+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
+ if (!dev)
+ {
+ return -EBADF;
+ }
+#endif
+ /* Make sure that we have exclusive access to the device structure */
+
+ if (sem_wait(&dev->d_bfsem) == 0)
+ {
+ /* If this the first reference on the device, then allocate the buffer */
+
+ if (dev->d_refs == 0)
+ {
+ dev->d_buffer = (ubyte*)malloc(CONFIG_DEV_PIPE_SIZE);
+ if (!dev->d_buffer)
+ {
+ (void)sem_post(&dev->d_bfsem);
+ return -ENOMEM;
+ }
+ }
+
+ /* Increment the reference count on the pipe instance */
+
+ dev->d_refs++;
+
+ /* If opened for writing, increment the count of writers on on the pipe instance */
+
+ if ((filep->f_oflags & O_WROK) != 0)
+ {
+ dev->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->d_nwriters == 1)
+ {
+ while (sem_getvalue(&dev->d_rdsem, &sval) == 0 && sval < 0)
+ {
+ sem_post(&dev->d_rdsem);
+ }
+ }
+ }
+
+ /* If opened for read-only, then wait for at least one writer on the pipe */
+
+ sched_lock();
+ (void)sem_post(&dev->d_bfsem);
+ if ((filep->f_oflags & O_RDWR) == O_RDONLY && dev->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->d_rdsem);
+ }
+ sched_unlock();
+ return OK;
+ }
+ return ERROR;
+}
+
+/****************************************************************************
+ * Name: pipecommon_close
+ ****************************************************************************/
+
+int pipecommon_close(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
+ if (!dev)
+ {
+ return -EBADF;
+ }
+#endif
+
+ /* Make sure that we have exclusive access to the device structure.
+ * NOTE: close() is supposed to return EINTR if interrupted, however
+ * I've never seen anyone check that.
+ */
+
+ pipecommon_semtake(&dev->d_bfsem);
+
+ /* Check if the decremented reference count would go to zero */
+
+ if (dev->d_refs > 1)
+ {
+ /* No.. then just decrement the reference count */
+
+ dev->d_refs--;
+
+ /* If opened for writing, decrement the count of writers on on the pipe instance */
+
+ if ((filep->f_oflags & O_WROK) != 0)
+ {
+ /* If there are no longer any writers on the pipe, then notify all of the
+ * waiting readers that they must return end-of-file.
+ */
+
+ if (--dev->d_nwriters <= 0)
+ {
+ while (sem_getvalue(&dev->d_rdsem, &sval) == 0 && sval < 0)
+ {
+ sem_post(&dev->d_rdsem);
+ }
+ }
+ }
+ }
+ else
+ {
+ /* Yes... deallocate the buffer */
+
+ free(dev->d_buffer);
+ dev->d_buffer = NULL;
+
+ /* And reset all counts and indices */
+
+ dev->d_wrndx = 0;
+ dev->d_rdndx = 0;
+ dev->d_refs = 0;
+ dev->d_nwriters = 0;
+ }
+
+ sem_post(&dev->d_bfsem);
+ return OK;
+}
+
+/****************************************************************************
+ * Name: pipecommon_read
+ ****************************************************************************/
+
+ssize_t pipecommon_read(FAR struct file *filep, FAR char *buffer, size_t len)
+{
+ struct inode *inode = filep->f_inode;
+ struct pipe_dev_s *dev = inode->i_private;
+#ifdef CONFIG_DEV_PIPEDUMP
+ FAR ubyte *start = (ubyte*)buffer;
+#endif
+ ssize_t nread = 0;
+ int sval;
+ int ret;
+
+ /* Some sanity checking */
+#if CONFIG_DEBUG
+ if (!dev)
+ {
+ return -ENODEV;
+ }
+#endif
+
+ /* Make sure that we have exclusive access to the device structure */
+
+ if (sem_wait(&dev->d_bfsem) < 0)
+ {
+ return ERROR;
+ }
+
+ /* If the pipe is empty, then wait for something to be written to it */
+
+ while (dev->d_wrndx == dev->d_rdndx)
+ {
+ /* If O_NONBLOCK was set, then return EGAIN */
+
+ if (filep->f_oflags & O_NONBLOCK)
+ {
+ sem_post(&dev->d_bfsem);
+ return -EAGAIN;
+ }
+
+ /* If there are no writers on the pipe, then return end of file */
+
+ if (dev->d_nwriters <= 0)
+ {
+ sem_post(&dev->d_bfsem);
+ return 0;
+ }
+
+ /* Otherwise, wait for something to be written to the pipe */
+
+ sched_lock();
+ sem_post(&dev->d_bfsem);
+ ret = sem_wait(&dev->d_rdsem);
+ sched_unlock();
+
+ if (ret < 0 || sem_wait(&dev->d_bfsem) < 0)
+ {
+ return ERROR;
+ }
+ }
+
+ /* Then return whatever is available in the pipe (which is at least one byte) */
+
+ nread = 0;
+ while (nread < len && dev->d_wrndx != dev->d_rdndx)
+ {
+ *buffer++ = dev->d_buffer[dev->d_rdndx];
+ if (++dev->d_rdndx >= CONFIG_DEV_PIPE_SIZE)
+ {
+ dev->d_rdndx = 0;
+ }
+ nread++;
+ }
+
+ /* Notify all waiting writers that bytes have been removed from the buffer */
+
+ while (sem_getvalue(&dev->d_wrsem, &sval) == 0 && sval < 0)
+ {
+ sem_post(&dev->d_wrsem);
+ }
+
+ /* Notify all poll/select waiters that they can write to the FIFO */
+
+ pipecommon_pollnotify(dev, POLLOUT);
+
+ sem_post(&dev->d_bfsem);
+ pipe_dumpbuffer("From PIPE:", start, nread);
+ return nread;
+}
+
+/****************************************************************************
+ * Name: pipecommon_write
+ ****************************************************************************/
+
+ssize_t pipecommon_write(FAR struct file *filep, FAR const char *buffer, size_t len)
+{
+ struct inode *inode = filep->f_inode;
+ struct pipe_dev_s *dev = inode->i_private;
+ ssize_t nwritten = 0;
+ ssize_t last;
+ int nxtwrndx;
+ int sval;
+
+ /* Some sanity checking */
+
+#if CONFIG_DEBUG
+ if (!dev)
+ {
+ return -ENODEV;
+ }
+#endif
+ pipe_dumpbuffer("To PIPE:", (ubyte*)buffer, len);
+
+ /* At present, this method cannot be called from interrupt handlers. That is
+ * because it calls sem_wait (via pipecommon_semtake below) and sem_wait cannot
+ * be called from interrupt level. This actually happens fairly commonly
+ * IF dbg() is called from interrupt handlers and stdout is being redirected
+ * via a pipe. In that case, the debug output will try to go out the pipe
+ * (interrupt handlers should use the lldbg() APIs).
+ *
+ * On the other hand, it would be very valuable to be able to feed the pipe
+ * from an interrupt handler! TODO: Consider disabling interrupts instead
+ * of taking semaphores so that pipes can be written from interupt handlers
+ */
+
+ DEBUGASSERT(up_interrupt_context() == FALSE)
+
+ /* Make sure that we have exclusive access to the device structure */
+
+ if (sem_wait(&dev->d_bfsem) < 0)
+ {
+ return ERROR;
+ }
+
+ /* Loop until all of the bytes have been written */
+
+ last = 0;
+ for (;;)
+ {
+ /* Calculate the write index AFTER the next byte is written */
+
+ nxtwrndx = dev->d_wrndx + 1;
+ if (nxtwrndx >= CONFIG_DEV_PIPE_SIZE)
+ {
+ nxtwrndx = 0;
+ }
+
+ /* Would the next write overflow the circular buffer? */
+
+ if (nxtwrndx != dev->d_rdndx)
+ {
+ /* No... copy the byte */
+
+ dev->d_buffer[dev->d_wrndx] = *buffer++;
+ dev->d_wrndx = nxtwrndx;
+
+ /* Is the write complete? */
+
+ if (++nwritten >= len)
+ {
+ /* Yes.. Notify all of the waiting readers that more data is available */
+
+ while (sem_getvalue(&dev->d_rdsem, &sval) == 0 && sval < 0)
+ {
+ sem_post(&dev->d_rdsem);
+ }
+
+ /* Notify all poll/select waiters that they can write to the FIFO */
+
+ pipecommon_pollnotify(dev, POLLIN);
+
+ /* Return the number of bytes written */
+
+ sem_post(&dev->d_bfsem);
+ return len;
+ }
+ }
+ else
+ {
+ /* There is not enough room for the next byte. Was anything written in this pass? */
+
+ if (last < nwritten)
+ {
+ /* Yes.. Notify all of the waiting readers that more data is available */
+
+ while (sem_getvalue(&dev->d_rdsem, &sval) == 0 && sval < 0)
+ {
+ sem_post(&dev->d_rdsem);
+ }
+ }
+ last = nwritten;
+
+ /* If O_NONBLOCK was set, then return partial bytes written or EGAIN */
+
+ if (filep->f_oflags & O_NONBLOCK)
+ {
+ if (nwritten == 0)
+ {
+ nwritten = -EAGAIN;
+ }
+ sem_post(&dev->d_bfsem);
+ return nwritten;
+ }
+
+ /* There is more to be written.. wait for data to be removed from the pipe */
+
+ sched_lock();
+ sem_post(&dev->d_bfsem);
+ pipecommon_semtake(&dev->d_wrsem);
+ sched_unlock();
+ pipecommon_semtake(&dev->d_bfsem);
+ }
+ }
+}
+
+/****************************************************************************
+ * Name: pipecommon_poll
+ ****************************************************************************/
+
+#ifndef CONFIG_DISABLE_POLL
+int pipecommon_poll(FAR struct file *filep, FAR struct pollfd *fds,
+ boolean setup)
+{
+ FAR struct inode *inode = filep->f_inode;
+ FAR struct pipe_dev_s *dev = inode->i_private;
+ pollevent_t eventset;
+ pipe_ndx_t nbytes;
+ int ret = OK;
+ int i;
+
+ /* Some sanity checking */
+
+#if CONFIG_DEBUG
+ if (!dev || !fds)
+ {
+ return -ENODEV;
+ }
+#endif
+
+ /* Are we setting up the poll? Or tearing it down? */
+
+ pipecommon_semtake(&dev->d_bfsem);
+ if (setup)
+ {
+ /* This is a request to set up the poll. Find an available
+ * slot for the poll structure reference
+ */
+
+ for (i = 0; i < CONFIG_DEV_PIPE_NPOLLWAITERS; i++)
+ {
+ /* Find an available slot */
+
+ if (!dev->d_fds[i])
+ {
+ /* Bind the poll structure and this slot */
+
+ dev->d_fds[i] = fds;
+ fds->priv = &dev->d_fds[i];
+ break;
+ }
+ }
+
+ if (i >= CONFIG_DEV_PIPE_NPOLLWAITERS)
+ {
+ fds->priv = NULL;
+ ret = -EBUSY;
+ goto errout;
+ }
+
+ /* Should immediately notify on any of the requested events?
+ * First, determine how many bytes are in the buffer
+ */
+
+ if (dev->d_wrndx >= dev->d_rdndx)
+ {
+ nbytes = dev->d_wrndx - dev->d_rdndx;
+ }
+ else
+ {
+ nbytes = (CONFIG_DEV_PIPE_SIZE-1) + dev->d_wrndx - dev->d_rdndx;
+ }
+
+ /* Notify the POLLOUT event if the pipe is not full */
+
+ eventset = 0;
+ if (nbytes < (CONFIG_DEV_PIPE_SIZE-1))
+ {
+ eventset |= POLLOUT;
+ }
+
+ /* Notify the POLLIN event if the pipe is not empty */
+
+ if (nbytes > 0)
+ {
+ eventset |= POLLIN;
+ }
+
+ if (eventset)
+ {
+ pipecommon_pollnotify(dev, eventset);
+ }
+ }
+ else
+ {
+ /* This is a request to tear down the poll. */
+
+ struct pollfd **slot = (struct pollfd **)fds->priv;
+
+#ifdef CONFIG_DEBUG
+ if (!slot)
+ {
+ ret = -EIO;
+ goto errout;
+ }
+#endif
+
+ /* Remove all memory of the poll setup */
+
+ *slot = NULL;
+ fds->priv = NULL;
+ }
+
+errout:
+ sem_post(&dev->d_bfsem);
+ return ret;
+}
+#endif
+
+#endif /* CONFIG_DEV_PIPE_SIZE > 0 */
diff --git a/nuttx/drivers/pipes/pipe_common.h b/nuttx/drivers/pipes/pipe_common.h
new file mode 100644
index 000000000..9e9f27fc1
--- /dev/null
+++ b/nuttx/drivers/pipes/pipe_common.h
@@ -0,0 +1,136 @@
+/****************************************************************************
+ * drivers/pipe/pipe_common.h
+ *
+ * Copyright (C) 2008i-2009 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+#ifndef __DRIVERS_PIPE_COMMON_H
+#define __DRIVERS_PIPE_COMMON_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <sys/types.h>
+#include <poll.h>
+
+#ifndef CONFIG_DEV_PIPE_SIZE
+# define CONFIG_DEV_PIPE_SIZE 1024
+#endif
+
+#if CONFIG_DEV_PIPE_SIZE > 0
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+
+/* Maximum number of threads than can be waiting for POLL events */
+
+#ifndef CONFIG_DEV_PIPE_NPOLLWAITERS
+# define CONFIG_DEV_PIPE_NPOLLWAITERS 2
+#endif
+
+/* Maximum number of open's supported on pipe */
+
+#define CONFIG_DEV_PIPE_MAXUSER 255
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/* Make the buffer index as small as possible for the configured pipe size */
+
+#if CONFIG_DEV_PIPE_SIZE > 65535
+typedef uint32 pipe_ndx_t; /* 32-bit index */
+#elif CONFIG_DEV_PIPE_SIZE > 255
+typedef uint16 pipe_ndx_t; /* 16-bit index */
+#else
+typedef ubyte pipe_ndx_t; /* 8-bit index */
+#endif
+
+/* This structure represents the state of one pipe. A reference to this
+ * structure is retained in the i_private field of the inode whenthe pipe/fifo
+ * device is registered.
+ */
+
+struct pipe_dev_s
+{
+ sem_t d_bfsem; /* Used to serialize access to d_buffer and indices */
+ sem_t d_rdsem; /* Empty buffer - Reader waits for data write */
+ sem_t d_wrsem; /* Full buffer - Writer waits for data read */
+ pipe_ndx_t d_wrndx; /* Index in d_buffer to save next byte written */
+ pipe_ndx_t d_rdndx; /* Index in d_buffer to return the next byte read */
+ ubyte d_refs; /* References counts on pipe (limited to 255) */
+ ubyte d_nwriters; /* Number of reference counts for write access */
+ ubyte d_pipeno; /* Pipe minor number */
+ ubyte *d_buffer; /* Buffer allocated when device opened */
+
+ /* The following is a list if poll structures of threads waiting for
+ * driver events. The 'struct pollfd' reference for each open is also
+ * retained in the f_priv field of the 'struct file'.
+ */
+
+#ifndef CONFIG_DISABLE_POLL
+ struct pollfd *d_fds[CONFIG_DEV_PIPE_NPOLLWAITERS];
+#endif
+};
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+#ifdef __cplusplus
+# define EXTERN extern "C"
+extern "C" {
+#else
+# define EXTERN extern
+#endif
+
+EXTERN FAR struct pipe_dev_s *pipecommon_allocdev(void);
+EXTERN void pipecommon_freedev(FAR struct pipe_dev_s *dev);
+EXTERN int pipecommon_open(FAR struct file *filep);
+EXTERN int pipecommon_close(FAR struct file *filep);
+EXTERN ssize_t pipecommon_read(FAR struct file *, FAR char *, size_t);
+EXTERN ssize_t pipecommon_write(FAR struct file *, FAR const char *, size_t);
+#ifndef CONFIG_DISABLE_POLL
+EXTERN int pipecommon_poll(FAR struct file *filep, FAR struct pollfd *fds,
+ boolean setup);
+#endif
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CONFIG_DEV_PIPE_SIZE > 0 */
+#endif /* __DRIVERS_PIPE_COMMON_H */