From 68ec2ba09880ab996cbb6e9a3ad86c04ab7bc860 Mon Sep 17 00:00:00 2001 From: patacongo Date: Mon, 17 Nov 2008 20:24:28 +0000 Subject: [PATCH] Add poll() method git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@1262 42af7a65-404d-4744-a932-0658087f49c3 --- drivers/dev_null.c | 29 ++++++++- drivers/dev_zero.c | 37 +++++++++++- drivers/fifo.c | 6 +- drivers/pipe.c | 6 +- drivers/pipe_common.c | 137 +++++++++++++++++++++++++++++++++++++++++- drivers/pipe_common.h | 30 ++++++++- 6 files changed, 235 insertions(+), 10 deletions(-) diff --git a/drivers/dev_null.c b/drivers/dev_null.c index f097f76c91..8db8c3cbb2 100644 --- a/drivers/dev_null.c +++ b/drivers/dev_null.c @@ -45,6 +45,7 @@ #include #include +#include #include #include @@ -54,6 +55,9 @@ static ssize_t devnull_read(FAR struct file *, FAR char *, size_t); static ssize_t devnull_write(FAR struct file *, FAR const char *, size_t); +#ifndef CONFIG_DISABLE_POLL +static int devnull_poll(FAR struct file *filp, FAR struct pollfd *poll); +#endif /**************************************************************************** * Private Data @@ -66,8 +70,10 @@ static struct file_operations devnull_fops = devnull_read, /* read */ devnull_write, /* write */ 0, /* seek */ - 0, /* ioctl */ - 0 /* poll */ + 0 /* ioctl */ +#ifndef CONFIG_DISABLE_POLL + , devnull_poll /* poll */ +#endif }; /**************************************************************************** @@ -92,6 +98,25 @@ static ssize_t devnull_write(FAR struct file *filp, FAR const char *buffer, size return len; /* Say that everything was written */ } +/**************************************************************************** + * Name: devnull_poll + ****************************************************************************/ + +#ifndef CONFIG_DISABLE_POLL +static int devnull_poll(FAR struct file *filp, FAR struct pollfd *fds) +{ + if (fds) + { + fds->revents |= (fds->events & (POLLIN|POLLOUT)); + if (fds->revents != 0) + { + sem_post(fds->sem); + } + } + return OK; +} +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ diff --git a/drivers/dev_zero.c b/drivers/dev_zero.c index 876734770a..08815ace5b 100644 --- a/drivers/dev_zero.c +++ b/drivers/dev_zero.c @@ -45,6 +45,7 @@ #include #include +#include #include #include @@ -54,6 +55,9 @@ static ssize_t devzero_read(FAR struct file *, FAR char *, size_t); static ssize_t devzero_write(FAR struct file *, FAR const char *, size_t); +#ifndef CONFIG_DISABLE_POLL +static int devzero_poll(FAR struct file *filp, FAR struct pollfd *fds); +#endif /**************************************************************************** * Private Data @@ -66,25 +70,54 @@ static struct file_operations devzero_fops = devzero_read, /* read */ devzero_write, /* write */ 0, /* seek */ - 0, /* ioctl */ - 0 /* poll */ + 0 /* ioctl */ +#ifndef CONFIG_DISABLE_POLL + , devzero_poll /* poll */ +#endif }; /**************************************************************************** * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: devzero_read + ****************************************************************************/ + static ssize_t devzero_read(FAR struct file *filp, FAR char *buffer, size_t len) { memset(buffer, 0, len); return len; } +/**************************************************************************** + * Name: devzero_write + ****************************************************************************/ + static ssize_t devzero_write(FAR struct file *filp, FAR const char *buffer, size_t len) { return len; } +/**************************************************************************** + * Name: devzero_poll + ****************************************************************************/ + +#ifndef CONFIG_DISABLE_POLL +static int devzero_poll(FAR struct file *filp, FAR struct pollfd *fds) +{ + if (fds) + { + fds->revents |= (fds->events & (POLLIN|POLLOUT)); + if (fds->revents != 0) + { + sem_post(fds->sem); + } + } + return OK; +} +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ diff --git a/drivers/fifo.c b/drivers/fifo.c index fb17e34612..7775af9ae0 100644 --- a/drivers/fifo.c +++ b/drivers/fifo.c @@ -74,8 +74,10 @@ static struct file_operations fifo_fops = pipecommon_read, /* read */ pipecommon_write, /* write */ 0, /* seek */ - 0, /* ioctl */ - 0 /* poll */ + 0 /* ioctl */ +#ifndef CONFIG_DISABLE_POLL + , pipecommon_poll /* poll */ +#endif }; /**************************************************************************** diff --git a/drivers/pipe.c b/drivers/pipe.c index 7e4581c8ad..4ad5f0f992 100644 --- a/drivers/pipe.c +++ b/drivers/pipe.c @@ -82,8 +82,10 @@ static struct file_operations pipe_fops = pipecommon_read, /* read */ pipecommon_write, /* write */ 0, /* seek */ - 0, /* ioctl */ - 0, /* pipe */ + 0 /* ioctl */ +#ifndef CONFIG_DISABLE_POLL + , pipecommon_poll /* poll */ +#endif }; static sem_t g_pipesem = { 1 }; diff --git a/drivers/pipe_common.c b/drivers/pipe_common.c index 59b9f79c8e..f00705f70e 100644 --- a/drivers/pipe_common.c +++ b/drivers/pipe_common.c @@ -52,6 +52,8 @@ #include #include #include +#include + #include #include "pipe_common.h" @@ -96,6 +98,33 @@ static void pipecommon_semtake(sem_t *sem) } } +/**************************************************************************** + * 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 ****************************************************************************/ @@ -168,6 +197,10 @@ int pipecommon_open(FAR struct file *filep) } } + /* There is no, file-specific private data (at least not yet) */ + + filep->f_priv = NULL; + /* Increment the reference count on the pipe instance */ dev->d_refs++; @@ -335,6 +368,7 @@ ssize_t pipecommon_read(FAR struct file *filep, FAR char *buffer, size_t len) sem_post(&dev->d_bfsem); ret = sem_wait(&dev->d_rdsem); sched_unlock(); + if (ret < 0 || sem_wait(&dev->d_bfsem) < 0) { return ERROR; @@ -361,8 +395,12 @@ ssize_t pipecommon_read(FAR struct file *filep, FAR char *buffer, size_t len) 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); - return nread; + return nread; } /**************************************************************************** @@ -426,6 +464,10 @@ ssize_t pipecommon_write(FAR struct file *filep, FAR const char *buffer, size_t 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); @@ -470,4 +512,97 @@ ssize_t pipecommon_write(FAR struct file *filep, FAR const char *buffer, size_t } } +/**************************************************************************** + * Name: pipecommon_poll + ****************************************************************************/ + +#ifndef CONFIG_DISABLE_POLL +int pipecommon_poll(FAR struct file *filep, FAR struct pollfd *fds) +{ + struct inode *inode = filep->f_inode; + struct pipe_dev_s *dev = inode->i_private; + pollevent_t eventset; + pipe_ndx_t nbytes; + int i; + + /* Some sanity checking */ +#if CONFIG_DEBUG + if (!dev) + { + return -ENODEV; + } +#endif + + /* Find an available slot for the poll structure reference */ + + pipecommon_semtake(&dev->d_bfsem); + for (i = 0; i < CONFIG_DEV_PIPE_NPOLLWAITERS; i++) + { + /* Find the slot with the value equal to filep->f_priv. If there + * is not previously installed poll structure, then f_priv will + * be NULL and we will find the first unused slot. If f_priv is + * is non-NULL, then we will find the slot that was used for the + * previous setup. + */ + + if (dev->d_fds[i] == filep->f_priv) + { + dev->d_fds[i] = fds; + break; + } + } + + if (i >= CONFIG_DEV_PIPE_NPOLLWAITERS) + { + DEBUGASSERT(fds == NULL); + return -EBUSY; + } + + /* Set or clear the poll event structure reference in the 'struct file' + * private data. + */ + + filep->f_priv = fds; + + /* Check if we should immediately notify on any of the requested events */ + + if (fds) + { + /* 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); + } + } + + sem_post(&dev->d_bfsem); + return OK; +} +#endif + #endif /* CONFIG_DEV_PIPE_SIZE > 0 */ diff --git a/drivers/pipe_common.h b/drivers/pipe_common.h index 34bde18c37..3b43b97b99 100644 --- a/drivers/pipe_common.h +++ b/drivers/pipe_common.h @@ -42,16 +42,24 @@ #include #include +#include #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 @@ -70,6 +78,11 @@ typedef uint16 pipe_ndx_t; /* 16-bit index */ 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 */ @@ -80,9 +93,21 @@ struct pipe_dev_s 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 alloated when device opend */ + 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 ****************************************************************************/ @@ -100,6 +125,9 @@ 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); +#endif #undef EXTERN #ifdef __cplusplus