net/udp/udp_netpoll.c: Port TCP poll changes to UDP.
This commit is contained in:
parent
b3f0aab00a
commit
6e60af91e4
@ -67,7 +67,7 @@ struct tcp_poll_s
|
||||
FAR struct socket *psock; /* Needed to handle loss of connection */
|
||||
struct pollfd *fds; /* Needed to handle poll events */
|
||||
FAR struct devif_callback_s *cb; /* Needed to teardown the poll */
|
||||
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
|
||||
#if defined(CONFIG_NET_TCP_WRITE_BUFFERS) && defined(CONFIG_IOB_NOTIFIER)
|
||||
int16_t key; /* Needed to cancel pending notification */
|
||||
#endif
|
||||
};
|
||||
@ -197,34 +197,42 @@ static inline void tcp_iob_work(FAR void *arg)
|
||||
|
||||
if (!_SS_ISCONNECTED(psock->s_flags) && !_SS_ISLISTENING(psock->s_flags))
|
||||
{
|
||||
/* We were previously connected but lost the connection either due
|
||||
* to a graceful shutdown by the remote peer or because of some
|
||||
* exceptional event.
|
||||
*/
|
||||
/* Don't report more than once. Might happen in a race condition */
|
||||
|
||||
fds->revents |= (POLLERR | POLLHUP);
|
||||
if ((fds->revents & (POLLERR | POLLHUP)) == 0)
|
||||
{
|
||||
/* We were previously connected but lost the connection either due
|
||||
* to a graceful shutdown by the remote peer or because of some
|
||||
* exceptional event.
|
||||
*/
|
||||
|
||||
fds->revents |= (POLLERR | POLLHUP);
|
||||
nxsem_post(fds->sem);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if we are now able to send */
|
||||
/* Handle a race condition. Check if we have already posted the POLLOUT
|
||||
* event. If so, don't do it again and don't setup notification again.
|
||||
*/
|
||||
|
||||
else if (_SS_ISCONNECTED(psock->s_flags) && psock_tcp_cansend(psock) >= 0)
|
||||
if ((fds->events && POLLWRNORM) == 0 ||
|
||||
(fds->revents && POLLWRNORM) != 0)
|
||||
{
|
||||
fds->revents |= (POLLWRNORM & fds->events);
|
||||
}
|
||||
/* Check if we are now able to send */
|
||||
|
||||
/* Check if any requested events are already in effect */
|
||||
if (psock_tcp_cansend(psock) >= 0)
|
||||
{
|
||||
/* Yes.. then signal the poll logic */
|
||||
|
||||
if (fds->revents != 0)
|
||||
{
|
||||
/* Yes.. then signal the poll logic */
|
||||
fds->revents |= POLLWRNORM;
|
||||
nxsem_post(fds->sem);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No.. ask for the IOB free notification again */
|
||||
|
||||
nxsem_post(fds->sem);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No.. ask for the IOB free notification again */
|
||||
|
||||
pinfo->key = iob_notifier_setup(LPWORK, tcp_iob_work, pinfo);
|
||||
pinfo->key = iob_notifier_setup(LPWORK, tcp_iob_work, pinfo);
|
||||
}
|
||||
}
|
||||
|
||||
/* Protocol for the use of the IOB notifier is that we free the argument
|
||||
@ -240,7 +248,7 @@ static inline void tcp_iob_work(FAR void *arg)
|
||||
*
|
||||
* Description:
|
||||
* Notify the appropriate device driver that we are have data ready to
|
||||
* be send (TCP)
|
||||
* be sent (TCP)
|
||||
*
|
||||
* Input Parameters:
|
||||
* psock - Socket state structure
|
||||
@ -250,7 +258,7 @@ static inline void tcp_iob_work(FAR void *arg)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CONFIG_NET_TCP_WRITE_BUFFERS
|
||||
#if !defined(CONFIG_NET_TCP_WRITE_BUFFERS) || !defined(CONFIG_IOB_NOTIFIER)
|
||||
static inline void tcp_poll_txnotify(FAR struct socket *psock)
|
||||
{
|
||||
FAR struct tcp_conn_s *conn = psock->s_conn;
|
||||
@ -346,7 +354,7 @@ int tcp_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds)
|
||||
info->psock = psock;
|
||||
info->fds = fds;
|
||||
info->cb = cb;
|
||||
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
|
||||
#if defined(CONFIG_NET_TCP_WRITE_BUFFERS) && defined(CONFIG_IOB_NOTIFIER)
|
||||
info->key = 0;
|
||||
#endif
|
||||
|
||||
@ -519,7 +527,7 @@ int tcp_pollteardown(FAR struct socket *psock, FAR struct pollfd *fds)
|
||||
DEBUGASSERT(info != NULL && info->fds != NULL && info->cb != NULL);
|
||||
if (info != NULL)
|
||||
{
|
||||
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
|
||||
#if defined(CONFIG_NET_TCP_WRITE_BUFFERS) && defined(CONFIG_IOB_NOTIFIER)
|
||||
/* Cancel any pending IOB free notification */
|
||||
|
||||
if (info->key > 0)
|
||||
|
@ -964,7 +964,7 @@ errout:
|
||||
* psock An instance of the internal socket structure.
|
||||
*
|
||||
* Returned Value:
|
||||
* -ENOSYS (Function not implemented).
|
||||
* -ENOSYS (Function not implemented, always have to wait to send).
|
||||
*
|
||||
* Assumptions:
|
||||
* None
|
||||
@ -973,8 +973,6 @@ errout:
|
||||
|
||||
int psock_tcp_cansend(FAR struct socket *psock)
|
||||
{
|
||||
/* TODO: return OK unless someone is waiting for a packet to send */
|
||||
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
|
@ -45,6 +45,8 @@
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/kmalloc.h>
|
||||
#include <nuttx/wqueue.h>
|
||||
#include <nuttx/mm/iob.h>
|
||||
#include <nuttx/net/net.h>
|
||||
|
||||
#include "devif/devif.h"
|
||||
@ -65,6 +67,9 @@ struct udp_poll_s
|
||||
FAR struct net_driver_s *dev; /* Needed to free the callback structure */
|
||||
struct pollfd *fds; /* Needed to handle poll events */
|
||||
FAR struct devif_callback_s *cb; /* Needed to teardown the poll */
|
||||
#if defined(CONFIG_NET_UDP_WRITE_BUFFERS) && defined(CONFIG_IOB_NOTIFIER)
|
||||
int16_t key; /* Needed to cancel pending notification */
|
||||
#endif
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
@ -145,11 +150,10 @@ static uint16_t udp_poll_eventhandler(FAR struct net_driver_s *dev,
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: udp_poll_txnotify
|
||||
* Name: udp_iob_work
|
||||
*
|
||||
* Description:
|
||||
* Notify the appropriate device driver that we are have data ready to
|
||||
* be send (TCP)
|
||||
* Work thread callback function execute when an IOB because available.
|
||||
*
|
||||
* Input Parameters:
|
||||
* psock - Socket state structure
|
||||
@ -159,7 +163,75 @@ static uint16_t udp_poll_eventhandler(FAR struct net_driver_s *dev,
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CONFIG_NET_UDP_WRITE_BUFFERS
|
||||
#if defined(CONFIG_NET_UDP_WRITE_BUFFERS) && defined(CONFIG_IOB_NOTIFIER)
|
||||
static inline void udp_iob_work(FAR void *arg)
|
||||
{
|
||||
FAR struct work_notifier_entry_s *entry;
|
||||
FAR struct work_notifier_s *ninfo;
|
||||
FAR struct udp_poll_s *pinfo;
|
||||
FAR struct socket *psock;
|
||||
FAR struct pollfd *fds;
|
||||
|
||||
entry = (FAR struct work_notifier_entry_s *)arg;
|
||||
DEBUGASSERT(entry != NULL);
|
||||
|
||||
ninfo = &entry->info;
|
||||
DEBUGASSERT(ninfo->arg != NULL);
|
||||
|
||||
pinfo = (FAR struct udp_poll_s *)ninfo->arg;
|
||||
DEBUGASSERT(pinfo->psock != NULL && pinfo->fds != NULL);
|
||||
|
||||
psock = pinfo->psock;
|
||||
fds = pinfo->fds;
|
||||
|
||||
/* Handle a race condition. Check if we have already posted the POLLOUT
|
||||
* event. If so, don't do it again.
|
||||
*/
|
||||
|
||||
if ((fds->events && POLLWRNORM) == 0 ||
|
||||
(fds->revents && POLLWRNORM) != 0)
|
||||
{
|
||||
/* Check if we are now able to send */
|
||||
|
||||
if (psock_udp_cansend(psock) >= 0)
|
||||
{
|
||||
/* Yes.. then signal the poll logic */
|
||||
|
||||
fds->revents |= POLLWRNORM;
|
||||
nxsem_post(fds->sem);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No.. ask for the IOB free notification again */
|
||||
|
||||
pinfo->key = iob_notifier_setup(LPWORK, udp_iob_work, pinfo);
|
||||
}
|
||||
}
|
||||
|
||||
/* Protocol for the use of the IOB notifier is that we free the argument
|
||||
* after the notification has been processed.
|
||||
*/
|
||||
|
||||
kmm_free(arg);
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: udp_poll_txnotify
|
||||
*
|
||||
* Description:
|
||||
* Notify the appropriate device driver that we are have data ready to
|
||||
* be sent (UDP)
|
||||
*
|
||||
* Input Parameters:
|
||||
* psock - Socket state structure
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#if !defined(CONFIG_NET_UDP_WRITE_BUFFERS) || !defined(CONFIG_IOB_NOTIFIER)
|
||||
static inline void udp_poll_txnotify(FAR struct socket *psock)
|
||||
{
|
||||
FAR struct udp_conn_s *conn = psock->s_conn;
|
||||
@ -262,6 +334,9 @@ int udp_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds)
|
||||
info->psock = psock;
|
||||
info->fds = fds;
|
||||
info->cb = cb;
|
||||
#if defined(CONFIG_NET_UDP_WRITE_BUFFERS) && defined(CONFIG_IOB_NOTIFIER)
|
||||
info->key = 0;
|
||||
#endif
|
||||
|
||||
/* Initialize the callback structure. Save the reference to the info
|
||||
* structure as callback private data so that it will be available during
|
||||
@ -302,6 +377,13 @@ int udp_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds)
|
||||
fds->revents |= (POLLRDNORM & fds->events);
|
||||
}
|
||||
|
||||
if (psock_udp_cansend(psock) >= 0)
|
||||
{
|
||||
/* Normal data may be sent without blocking (at least one byte). */
|
||||
|
||||
fds->revents |= (POLLWRNORM & fds->events);
|
||||
}
|
||||
|
||||
/* Check if any requested events are already in effect */
|
||||
|
||||
if (fds->revents != 0)
|
||||
@ -311,7 +393,20 @@ int udp_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds)
|
||||
nxsem_post(fds->sem);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_NET_UDP_WRITE_BUFFERS
|
||||
#if defined(CONFIG_NET_UDP_WRITE_BUFFERS) && defined(CONFIG_IOB_NOTIFIER)
|
||||
/* If (1) revents == 0, (2) write buffering is enabled, and (3) the
|
||||
* POLLOUT event is needed, then setup to receive a notification an IOB
|
||||
* is freed.
|
||||
*/
|
||||
|
||||
else if ((fds->events & POLLOUT) != 0)
|
||||
{
|
||||
/* Ask for the IOB free notification */
|
||||
|
||||
info->key = iob_notifier_setup(LPWORK, udp_iob_work, info);
|
||||
}
|
||||
|
||||
#else
|
||||
/* If (1) the socket is in a bound state via bind() or via the
|
||||
* UDP_BINDTODEVICE socket options, (2) revents == 0, (3) write buffering
|
||||
* is not enabled (determined by a configuration setting), and (3) the
|
||||
@ -394,9 +489,20 @@ int udp_pollteardown(FAR struct socket *psock, FAR struct pollfd *fds)
|
||||
/* Recover the socket descriptor poll state info from the poll structure */
|
||||
|
||||
info = (FAR struct udp_poll_s *)fds->priv;
|
||||
DEBUGASSERT(info && info->fds && info->cb);
|
||||
if (info)
|
||||
DEBUGASSERT(info != NULL && info->fds != NULL && info->cb != NULL);
|
||||
if (info != NULL)
|
||||
{
|
||||
#if defined(CONFIG_NET_UDP_WRITE_BUFFERS) && defined(CONFIG_IOB_NOTIFIER)
|
||||
/* Cancel any pending IOB free notification */
|
||||
|
||||
if (info->key > 0)
|
||||
{
|
||||
/* Ask for the IOB free notification */
|
||||
|
||||
iob_notifier_teardown(info->key);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Release the callback */
|
||||
|
||||
net_lock();
|
||||
|
@ -881,4 +881,51 @@ errout_with_lock:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: psock_udp_cansend
|
||||
*
|
||||
* Description:
|
||||
* psock_udp_cansend() returns a value indicating if a write to the socket
|
||||
* would block. No space in the buffer is actually reserved, so it is
|
||||
* possible that the write may still block if the buffer is filled by
|
||||
* another means.
|
||||
*
|
||||
* Input Parameters:
|
||||
* psock An instance of the internal socket structure.
|
||||
*
|
||||
* Returned Value:
|
||||
* OK
|
||||
* At least one byte of data could be successfully written.
|
||||
* -EWOULDBLOCK
|
||||
* There is no room in the output buffer.
|
||||
* -EBADF
|
||||
* An invalid descriptor was specified.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int psock_udp_cansend(FAR struct socket *psock)
|
||||
{
|
||||
/* Verify that we received a valid socket */
|
||||
|
||||
if (!psock || psock->s_crefs <= 0)
|
||||
{
|
||||
nerr("ERROR: Invalid socket\n");
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
/* In order to setup the send, we need to have at least one free write
|
||||
* buffer head and at least one free IOB to initialize the write buffer head.
|
||||
*
|
||||
* REVISIT: The send will still block if we are unable to buffer the entire
|
||||
* user-provided buffer which may be quite large. We will almost certainly
|
||||
* need to have more than one free IOB, but we don't know how many more.
|
||||
*/
|
||||
|
||||
if (udp_wrbuffer_test() < 0 || iob_navail(false) <= 0)
|
||||
{
|
||||
return -EWOULDBLOCK;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
#endif /* CONFIG_NET && CONFIG_NET_UDP && CONFIG_NET_UDP_WRITE_BUFFERS */
|
||||
|
@ -562,4 +562,28 @@ errout_with_lock:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: psock_udp_cansend
|
||||
*
|
||||
* Description:
|
||||
* psock_udp_cansend() returns a value indicating if a write to the socket
|
||||
* would block. It is still possible that the write may block if another
|
||||
* write occurs first.
|
||||
*
|
||||
* Input Parameters:
|
||||
* psock An instance of the internal socket structure.
|
||||
*
|
||||
* Returned Value:
|
||||
* -ENOSYS (Function not implemented, always have to wait to send).
|
||||
*
|
||||
* Assumptions:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int psock_udp_cansend(FAR struct socket *psock)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_NET_UDP */
|
||||
|
Loading…
x
Reference in New Issue
Block a user