9
0
Fork 0

Implement poll/select for sockets

git-svn-id: https://nuttx.svn.sourceforge.net/svnroot/nuttx/trunk@1277 7fd9a85b-ad96-42d3-883c-3090e2eb8679
This commit is contained in:
patacongo 2008-11-18 17:30:30 +00:00
parent c23d514aab
commit a5161eb56f
15 changed files with 345 additions and 58 deletions

View File

@ -571,4 +571,5 @@
full buffer of read data before return. This means that getc would stall when it needed
to refill the input buffer. The old behavior (read full blocks) might be useful in other
contexts, so it is still available within the driver as a configuration option.
* Implement poll() and select() support for TCP/IP sockets

View File

@ -1207,6 +1207,7 @@ nuttx-0.3.19 2008-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr>
full buffer of read data before return. This means that getc would stall when it needed
to refill the input buffer. The old behavior (read full blocks) might be useful in other
contexts, so it is still available within the driver as a configuration option.
* Implement poll() and select() support for TCP/IP sockets
pascal-0.1.3 2008-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr>

View File

@ -54,7 +54,7 @@
static ssize_t devconsole_read(struct file *, char *, size_t);
static ssize_t devconsole_write(struct file *, const char *, size_t);
#ifndef CONFIG_DISABLE_POLL
static int devconsole_poll(FAR struct file *filep, FAR struct pollfd *fds);
static int devconsole_poll(FAR struct file *filep, FAR struct pollfd *fds, boolean setup);
#endif
/****************************************************************************
@ -85,7 +85,7 @@ static ssize_t devconsole_write(struct file *filp, const char *buffer, size_t le
}
#ifndef CONFIG_DISABLE_POLL
static int devconsole_poll(FAR struct file *filep, FAR struct pollfd *fds)
static int devconsole_poll(FAR struct file *filep, FAR struct pollfd *fds, boolean setup)
{
return OK;
}

View File

@ -56,7 +56,7 @@
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);
static int devnull_poll(FAR struct file *filp, FAR struct pollfd *fds, boolean setup);
#endif
/****************************************************************************
@ -103,9 +103,9 @@ static ssize_t devnull_write(FAR struct file *filp, FAR const char *buffer, size
****************************************************************************/
#ifndef CONFIG_DISABLE_POLL
static int devnull_poll(FAR struct file *filp, FAR struct pollfd *fds)
static int devnull_poll(FAR struct file *filp, FAR struct pollfd *fds, boolean setup)
{
if (fds)
if (setup)
{
fds->revents |= (fds->events & (POLLIN|POLLOUT));
if (fds->revents != 0)

View File

@ -56,7 +56,7 @@
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);
static int devzero_poll(FAR struct file *filp, FAR struct pollfd *fds, boolean setup);
#endif
/****************************************************************************
@ -104,9 +104,9 @@ static ssize_t devzero_write(FAR struct file *filp, FAR const char *buffer, size
****************************************************************************/
#ifndef CONFIG_DISABLE_POLL
static int devzero_poll(FAR struct file *filp, FAR struct pollfd *fds)
static int devzero_poll(FAR struct file *filp, FAR struct pollfd *fds, boolean setup)
{
if (fds)
if (setup)
{
fds->revents |= (fds->events & (POLLIN|POLLOUT));
if (fds->revents != 0)

View File

@ -517,7 +517,7 @@ ssize_t pipecommon_write(FAR struct file *filep, FAR const char *buffer, size_t
****************************************************************************/
#ifndef CONFIG_DISABLE_POLL
int pipecommon_poll(FAR struct file *filep, FAR struct pollfd *fds)
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;
@ -539,7 +539,7 @@ int pipecommon_poll(FAR struct file *filep, FAR struct pollfd *fds)
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
* is no 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.
@ -547,14 +547,14 @@ int pipecommon_poll(FAR struct file *filep, FAR struct pollfd *fds)
if (dev->d_fds[i] == filep->f_priv)
{
dev->d_fds[i] = fds;
dev->d_fds[i] = (setup ? fds : NULL);
break;
}
}
if (i >= CONFIG_DEV_PIPE_NPOLLWAITERS)
{
DEBUGASSERT(fds == NULL);
DEBUGASSERT(setup);
return -EBUSY;
}
@ -562,13 +562,16 @@ int pipecommon_poll(FAR struct file *filep, FAR struct pollfd *fds)
* private data.
*/
filep->f_priv = fds;
/* Check if we should immediately notify on any of the requested events */
if (fds)
filep->f_priv = NULL; /* Assume teardown */
if (setup)
{
/* Determine how many bytes are in the buffer */
/* Set 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. First,
* Determine how many bytes are in the buffer
*/
if (dev->d_wrndx >= dev->d_rdndx)
{

View File

@ -123,7 +123,7 @@ 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);
EXTERN int pipecommon_poll(FAR struct file *filep, FAR struct pollfd *fds, boolean setup);
#endif
#undef EXTERN

View File

@ -79,7 +79,7 @@ static ssize_t uart_read(FAR struct file *filep, FAR char *buffer, size_t buflen
static ssize_t uart_write(FAR struct file *filep, FAR const char *buffer, size_t buflen);
static int uart_ioctl(FAR struct file *filep, int cmd, unsigned long arg);
#ifndef CONFIG_DISABLE_POLL
static int uart_poll(FAR struct file *filep, FAR struct pollfd *fds);
static int uart_poll(FAR struct file *filep, FAR struct pollfd *fds, boolean setup);
#endif
/************************************************************************************
@ -400,7 +400,7 @@ static int uart_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
****************************************************************************/
#ifndef CONFIG_DISABLE_POLL
int uart_poll(FAR struct file *filep, FAR struct pollfd *fds)
int uart_poll(FAR struct file *filep, FAR struct pollfd *fds, boolean setup)
{
FAR struct inode *inode = filep->f_inode;
FAR uart_dev_t *dev = inode->i_private;
@ -422,7 +422,7 @@ int uart_poll(FAR struct file *filep, FAR struct pollfd *fds)
for (i = 0; i < CONFIG_DEV_CONSOLE_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
* is no 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.
@ -430,14 +430,14 @@ int uart_poll(FAR struct file *filep, FAR struct pollfd *fds)
if (dev->fds[i] == filep->f_priv)
{
dev->fds[i] = fds;
dev->fds[i] = (setup ? fds : NULL);
break;
}
}
if (i >= CONFIG_DEV_CONSOLE_NPOLLWAITERS)
{
DEBUGASSERT(fds == NULL);
DEBUGASSERT(setup);
return -EBUSY;
}
@ -445,13 +445,12 @@ int uart_poll(FAR struct file *filep, FAR struct pollfd *fds)
* private data.
*/
filep->f_priv = fds;
/* Check if we should immediately notify on any of the requested events */
if (fds)
filep->f_priv = NULL; /* Assume teardown */
if (setup)
{
/* Check if the xmit buffer is full. */
/* Check if we should immediately notify on any of the requested events.
* First, check if the xmit buffer is full.
*/
eventset = 0;

View File

@ -93,7 +93,7 @@ static void poll_semtake(FAR sem_t *sem)
****************************************************************************/
#if CONFIG_NFILE_DESCRIPTORS > 0
static int poll_fdsetup(int fd, FAR struct pollfd *fds)
static int poll_fdsetup(int fd, FAR struct pollfd *fds, boolean setup)
{
FAR struct filelist *list;
FAR struct file *this_file;
@ -137,7 +137,7 @@ static int poll_fdsetup(int fd, FAR struct pollfd *fds)
{
/* Yes, then setup the poll */
ret = (int)inode->u.i_ops->poll(this_file, fds);
ret = (int)inode->u.i_ops->poll(this_file, fds, setup);
}
return ret;
}
@ -168,7 +168,7 @@ static inline int poll_setup(FAR struct pollfd *fds, nfds_t nfds, sem_t *sem)
/* Set up the poll */
ret = poll_fdsetup(fds[i].fd, &fds[i]);
ret = poll_fdsetup(fds[i].fd, &fds[i], TRUE);
if (ret < 0)
{
return ret;
@ -201,7 +201,7 @@ static inline int poll_teardown(FAR struct pollfd *fds, nfds_t nfds, int *count)
{
/* Teardown the poll */
status = poll_fdsetup(fds[i].fd, NULL);
status = poll_fdsetup(fds[i].fd, &fds[i], FALSE);
if (status < 0)
{
ret = status;

View File

@ -118,6 +118,7 @@
struct uip_driver_s; /* Forward reference */
struct uip_callback_s; /* Forward reference */
struct uip_conn
{
dq_entry_t node; /* Implements a doubly linked list */
@ -179,13 +180,13 @@ struct uip_conn
/* accept() is called when the TCP logic has created a connection */
void *accept_private;
int (*accept)(struct uip_conn *listener, struct uip_conn *conn);
FAR void *accept_private;
int (*accept)(FAR struct uip_conn *listener, struct uip_conn *conn);
/* connection_event() is called on any of the subset of connection-related events */
void *connection_private;
void (*connection_event)(struct uip_conn *conn, uint16 flags);
FAR void *connection_private;
void (*connection_event)(FAR struct uip_conn *conn, uint16 flags);
};
/* The following structure is used to handle read-ahead buffering for TCP

View File

@ -76,7 +76,7 @@ struct file_operations
off_t (*seek)(FAR struct file *filp, off_t offset, int whence);
int (*ioctl)(FAR struct file *filp, int cmd, unsigned long arg);
#ifndef CONFIG_DISABLE_POLL
int (*poll)(FAR struct file *filp, struct pollfd *fds);
int (*poll)(FAR struct file *filp, struct pollfd *fds, boolean setup);
#endif
/* The two structures need not be common after this point */

View File

@ -84,17 +84,17 @@ typedef uint16 socktimeo_t;
struct socket
{
int s_crefs; /* Reference count on the socket */
uint8 s_type; /* Protocol type: Only SOCK_STREAM or SOCK_DGRAM */
uint8 s_flags; /* See _SF_* definitions */
int s_crefs; /* Reference count on the socket */
uint8 s_type; /* Protocol type: Only SOCK_STREAM or SOCK_DGRAM */
uint8 s_flags; /* See _SF_* definitions */
#ifdef CONFIG_NET_SOCKOPTS
sockopt_t s_options; /* Selected socket options */
sockopt_t s_options; /* Selected socket options */
#ifndef CONFIG_DISABLE_CLOCK
socktimeo_t s_rcvtimeo; /* Receive timeout value (in deciseconds) */
socktimeo_t s_sndtimeo; /* Send timeout value (in deciseconds) */
socktimeo_t s_rcvtimeo; /* Receive timeout value (in deciseconds) */
socktimeo_t s_sndtimeo; /* Send timeout value (in deciseconds) */
#endif
#endif
void *s_conn; /* Connection: struct uip_conn or uip_udp_conn */
void *s_conn; /* Connection: struct uip_conn or uip_udp_conn */
};
/* This defines a list of sockets indexed by the socket descriptor */

View File

@ -108,6 +108,12 @@ struct pollfd
sem_t *sem; /* Pointer to semaphore used to post output event */
pollevent_t events; /* The input event flags */
pollevent_t revents; /* The output event flags */
/* The socket poll logic needs a place to retain state info */
#if CONFIG_NSOCKET_DESCRIPTORS > 0 && defined(CONFIG_NET_TCP) && CONFIG_NET_NTCP_READAHEAD_BUFFERS > 0
FAR void *private;
#endif
};
/****************************************************************************

View File

@ -1,7 +1,7 @@
/****************************************************************************
* net-internal.h
* net/net-internal.h
*
* Copyright (C) 2007 Gregory Nutt. All rights reserved.
* Copyright (C) 2007, 2008 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
*
* Redistribution and use in source and binary forms, with or without
@ -14,7 +14,7 @@
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name Gregory Nutt nor the names of its contributors may be
* 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.
*

View File

@ -49,7 +49,231 @@
#include "net-internal.h"
/****************************************************************************
* Global Functions
* Pre-processor Definitions
****************************************************************************/
/* Network polling can only be supported on TCP and only if read-ahead buffering
* is enabled (it could be supported on UDP as will if it also had read-ahead
* buffering.
*/
#if defined(CONFIG_DISABLE_POLL) && CONFIG_NSOCKET_DESCRIPTORS > 0 && \
defined(CONFIG_NET_TCP) && CONFIG_NET_NTCP_READAHEAD_BUFFERS > 0
# define HAVE_NETPOLL 1
#else
# undef HAVE_NETPOLL
#endif
/****************************************************************************
* Private Types
****************************************************************************/
struct net_poll_s
{
FAR struct pollfd *fds; /* The descriptor poll info */
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Function: poll_interrupt
*
* Description:
* This function is called from the interrupt level to perform the actual
* TCP receive operation via by the uIP layer.
*
* Parameters:
* dev The structure of the network driver that caused the interrupt
* conn The connection structure associated with the socket
* flags Set of events describing why the callback was invoked
*
* Returned Value:
* None
*
* Assumptions:
* Running at the interrupt level
*
****************************************************************************/
#ifdef HAVE_NETPOLL
static uint16 poll_interrupt(struct uip_driver_s *dev, FAR void *conn,
FAR void *pvprivate, uint16 flags)
{
struct pollfd *fds = (struct recvfrom_s *)pvprivate;
nvdbg("flags: %04x\n", flags);
/* 'private' might be null in some race conditions (?) */
if (fds)
{
pollevent_t eventset = 0;
/* Check for data availability events. */
if ((flags & UIP_NEWDATA) != 0)
{
eventset |= POLLIN & fds->events;
}
/* A poll is a sign that we are free to send data. */
if ((flags & UIP_POLL) != 0)
{
eventset |= POLLOUT & fds->events;
}
/* Check for a loss of connection events */
if ((flags & (UIP_CLOSE|UIP_ABORT|UIP_TIMEDOUT)) != 0)
{
eventset |= (POLLERR|POLLHUP);
}
if (eventset)
{
fds->revevents |= eventset;
sem_post(fds->sem);
}
}
return flags;
}
#endif /* HAVE_NETPOLL */
/****************************************************************************
* Function: net_pollsetup
*
* Description:
* Setup to monitor events on one TCP/IP socket
*
* Input Parameters:
* conn - The TCP/IP connection of interest
* fds - The structure describing the events to be monitored, OR NULL if
* this is a request to stop monitoring events.
*
* Returned Value:
* 0: Success; Negated errno on failure
*
****************************************************************************/
#ifdef HAVE_NETPOLL
static inline int net_pollsetup((FAR struct uip_conn *)conn, struct pollfd *fds)
{
FAR struct uip_callback_s *cb;
irqstate_t flags;
int ret;
/* Sanity check */
#ifdef CONFIG_DEBUG
if (!conn || !fds || fds->private)
{
ret = -EINVAL;
goto errout;
}
#endif
/* Some of the following must be atomic */
flags = irqsave();
/* Allocate a TCP/IP callback structure */
cb = uip_tcpcallbackalloc(conn);
if (!cb)
{
ret = -EBUSY;
goto errout_with_irq;
}
/* Initialize the callbcack structure */
cb->flags = UIP_NEWDATA|UIP_POLL|UIP_CLOSE|UIP_ABORT|UIP_TIMEDOUT;
cb->private = (FAR void *)fds;
cb->event = poll_interrupt;
/* Save the nps reference in the poll structure for use at teardown as well */
fds->private = (FAR void *)cb;
/* Check for read data availability now */
if (!sq_empty(&conn->readahead))
{
fds->revents = fds->events & POLLIN;
if (fds->revents != 0)
{
/* If data is available now, the signal the poll logic */
sem_post(fds->sem);
}
}
irqrestore(flags);
return OK;
errout_with_irq:
irqrestore(flags);
free(nps);
errout:
return ret;
}
#endif /* HAVE_NETPOLL */
/****************************************************************************
* Function: net_pollteardown
*
* Description:
* Teardown monitoring of events on an TCP/IP socket
*
* Input Parameters:
* conn - The TCP/IP connection of interest
*
* Returned Value:
* 0: Success; Negated errno on failure
*
****************************************************************************/
#ifdef HAVE_NETPOLL
static inline int net_pollteardown((FAR struct uip_conn *)conn, struct pollfd *fds)
{
FAR struct uip_callback_s *cb;
irqstate_t flags;
int ret;
/* Sanity check */
#ifdef CONFIG_DEBUG
if (!conn || !fds || !fds->private)
{
ret = -EINVAL;
goto errout;
}
#endif
/* Recover the socket descriptor poll state info from the poll structure */
cb = (FAR struct uip_callback_s *)fds->private;
if (cb)
{
/* Release the callback */
flags = irqsave();
uip_tcpcallbackfree(conn, cb);
irqrestore(flags);
/* Release the poll/select data slot */
fds->private = NULL;
}
return OK;
}
#endif /* HAVE_NETPOLL */
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
@ -59,22 +283,74 @@
* The standard poll() operation redirects operations on socket descriptors
* to this function.
*
* Parameters:
* Input Parameters:
* fd - The socket descriptor of interest
* fds - The structures describing events to be monitored, OR NULL if
* fds - The structure describing the events to be monitored, OR NULL if
* this is a request to stop monitoring events.
*
* Returned Value:
* TBD
* 0: Success; Negated errno on failure
*
****************************************************************************/
#ifndef CONFIG_DISABLE_POLL
int net_poll(int sockfd, struct pollfd *fds)
{
#ifdef CONFIG_CPP_HAVE_WARNING
# warning To be provided
#endif
#ifndef HAVE_NETPOLL
return -ENOSYS;
}
#else
FAR struct socket *psock;
int ret;
#endif /* CONFIG_NET&& !CONFIG_DISABLE_POLL */
/* Verify that non-NULL pointers were passed */
#ifdef CONFIG_DEBUG
if (!fds)
{
ret = -EINVAL;
goto errout;
}
#endif
/* Get the underlying socket structure and verify that the sockfd
* corresponds to valid, allocated socket
*/
psock = sockfd_socket(sockfd);
if (!psock || psock->s_crefs <= 0)
{
ret = -EBADF;
goto errout;
}
#ifdef CONFIG_NET_UDP
/* poll() not supported for UDP */
if (psock->s_type != SOCK_STREAM)
{
ret = -ENOSYS;
goto errout;
}
#endif
/* Check if we are setting up or tearing down the poll */
if (fds)
{
/* Perform the TCP/IP poll() setup */
ret = net_pollsetup((FAR struct uip_conn *)psock->conn, fds);
}
else
{
/* Perform the TCP/IP poll() teardown */
ret = net_pollteardown((FAR struct uip_conn *)psock->conn);
}
errout:
return ret;
#endif /* HAVE_NETPOLL */
}
#endif /* !CONFIG_DISABLE_POLL */
#endif /* CONFIG_NET && !CONFIG_DISABLE_POLL */