aboutsummaryrefslogtreecommitdiff
path: root/nuttx/drivers/pipes/pipe_common.c
diff options
context:
space:
mode:
Diffstat (limited to 'nuttx/drivers/pipes/pipe_common.c')
-rw-r--r--nuttx/drivers/pipes/pipe_common.c682
1 files changed, 0 insertions, 682 deletions
diff --git a/nuttx/drivers/pipes/pipe_common.c b/nuttx/drivers/pipes/pipe_common.c
deleted file mode 100644
index 5f61fdd8e..000000000
--- a/nuttx/drivers/pipes/pipe_common.c
+++ /dev/null
@@ -1,682 +0,0 @@
-/****************************************************************************
- * drivers/pipes/pipe_common.c
- *
- * Copyright (C) 2008-2009, 2011 Gregory Nutt. All rights reserved.
- * Author: Gregory Nutt <gnutt@nuttx.org>
- *
- * 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 <stdint.h>
-#include <stdbool.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/kmalloc.h>
-#include <nuttx/fs/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 *)kmalloc(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);
- kfree(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;
- int ret;
-
- /* Some sanity checking */
-#if CONFIG_DEBUG
- if (!dev)
- {
- return -EBADF;
- }
-#endif
-
- /* Make sure that we have exclusive access to the device structure. The
- * sem_wait() call should fail only if we are awakened by a signal.
- */
-
- ret = sem_wait(&dev->d_bfsem);
- if (ret != OK)
- {
- fdbg("sem_wait failed: %d\n", errno);
- DEBUGASSERT(errno > 0);
- return -errno;
- }
-
- /* If this the first reference on the device, then allocate the buffer */
-
- if (dev->d_refs == 0)
- {
- dev->d_buffer = (uint8_t*)kmalloc(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.
- */
-
- ret = sem_wait(&dev->d_rdsem);
- if (ret != OK)
- {
- /* The sem_wait() call should fail only if we are awakened by
- * a signal.
- */
-
- fdbg("sem_wait failed: %d\n", errno);
- DEBUGASSERT(errno > 0);
- ret = -errno;
-
- /* Immediately close the pipe that we just opened */
-
- (void)pipecommon_close(filep);
- }
- }
-
- sched_unlock();
- return ret;
-}
-
-/****************************************************************************
- * 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 */
-
- kfree(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 uint8_t *start = (uint8_t*)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:", (uint8_t*)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,
- bool 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 */