net/tcp/tcp_netpoll.c: Add logic to receive notifications when IOBs are freed (Needs CONFIG_NET_TCP_WRITE_BUFFERS and CONFIG_IOB_NOTIFIER). At present, does nothing because the logic in in psock_tcp_cansend() does not check for the availability of IOBs. That will change.

This commit is contained in:
Gregory Nutt 2018-09-11 12:00:42 -06:00
parent 4a1b8e5825
commit a680553f35
5 changed files with 126 additions and 23 deletions

View File

@ -45,9 +45,12 @@
#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"
#include "netdev/netdev.h"
#include "socket/socket.h"
#include "inet/inet.h"
#include "tcp/tcp.h"
@ -64,6 +67,9 @@ 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
int16_t key; /* Needed to cancel pending notification */
#endif
};
/****************************************************************************
@ -152,6 +158,73 @@ static uint16_t tcp_poll_eventhandler(FAR struct net_driver_s *dev,
return flags;
}
/****************************************************************************
* Name: tcp_iob_work
*
* Description:
* Work thread callback function execute when an IOB because available.
*
* Input Parameters:
* psock - Socket state structure
*
* Returned Value:
* None
*
****************************************************************************/
#if defined(CONFIG_NET_TCP_WRITE_BUFFERS) && defined(CONFIG_IOB_NOTIFIER)
static inline void tcp_iob_work(FAR void *arg)
{
FAR struct work_notifier_s *ninfo = (FAR struct work_notifier_s *)arg;
FAR struct tcp_poll_s *pinfo;
FAR struct socket *psock;
FAR struct pollfd *fds;
DEBUGASSERT(ninfo != NULL && ninfo->arg != NULL);
pinfo = (FAR struct tcp_poll_s *)ninfo->arg;
psock = pinfo->psock;
DEBUGASSERT(psock != NULL);
fds = pinfo->fds;
DEBUGASSERT(fds != NULL);
/* Verify that we still have a connection */
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.
*/
fds->revents |= (POLLERR | POLLHUP);
}
/* Check if we are now able to send */
else if (_SS_ISCONNECTED(psock->s_flags) && psock_tcp_cansend(psock) >= 0)
{
fds->revents |= (POLLWRNORM & fds->events);
}
/* Check if any requested events are already in effect */
if (fds->revents != 0)
{
/* Yes.. then signal the poll logic */
nxsem_post(fds->sem);
}
else
{
/* No.. ask for the IOB free notification again */
pinfo->key = iob_notifier_setup(LPWORK, tcp_iob_work, pinfo);
}
}
#endif
/****************************************************************************
* Name: tcp_poll_txnotify
*
@ -170,7 +243,7 @@ static uint16_t tcp_poll_eventhandler(FAR struct net_driver_s *dev,
#ifndef CONFIG_NET_TCP_WRITE_BUFFERS
static inline void tcp_poll_txnotify(FAR struct socket *psock)
{
FAR struct tcp_conn_s *conn = psock->conn;
FAR struct tcp_conn_s *conn = psock->s_conn;
#ifdef CONFIG_NET_IPv4
#ifdef CONFIG_NET_IPv6
@ -263,6 +336,9 @@ 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
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
@ -357,10 +433,23 @@ int tcp_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds)
nxsem_post(fds->sem);
}
#ifndef CONFIG_NET_TCP_WRITE_BUFFERS
#if defined(CONFIG_NET_TCP_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, tcp_iob_work, info);
}
#else
/* If (1) the socket is in a bound state, (2) revents == 0, (3) write
* buffering is not enabled (determined by a configuration setting), and
* (3) the POLLOUT event is needed then request an immediate Tx poll from
* (4) the POLLOUT event is needed then request an immediate Tx poll from
* the device associated with the binding.
*/
@ -417,9 +506,20 @@ int tcp_pollteardown(FAR struct socket *psock, FAR struct pollfd *fds)
/* Recover the socket descriptor poll state info from the poll structure */
info = (FAR struct tcp_poll_s *)fds->priv;
DEBUGASSERT(info && info->fds && info->cb);
if (info)
DEBUGASSERT(info != NULL && info->fds != NULL && info->cb != NULL);
if (info != NULL)
{
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
/* 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();

View File

@ -1239,7 +1239,7 @@ errout:
*
* Returned Value:
* OK
* At least one byte of data could be succesfully written.
* At least one byte of data could be successfully written.
* -EWOULDBLOCK
* There is no room in the output buffer.
* -EBADF

View File

@ -964,7 +964,7 @@ errout:
* psock An instance of the internal socket structure.
*
* Returned Value:
* OK (Function not implemented).
* -ENOSYS (Function not implemented).
*
* Assumptions:
* None
@ -975,7 +975,7 @@ int psock_tcp_cansend(FAR struct socket *psock)
{
/* TODO: return OK unless someone is waiting for a packet to send */
return OK;
return -ENOSYS;
}
#endif /* CONFIG_NET && CONFIG_NET_TCP && !CONFIG_NET_TCP_WRITE_BUFFERS */

View File

@ -47,8 +47,9 @@
#include <nuttx/kmalloc.h>
#include <nuttx/net/net.h>
#include <devif/devif.h>
#include <socket/socket.h>
#include "devif/devif.h"
#include "netdev/netdev.h"
#include "socket/socket.h"
#include "udp/udp.h"
#ifdef HAVE_UDP_POLL
@ -161,7 +162,7 @@ static uint16_t udp_poll_eventhandler(FAR struct net_driver_s *dev,
#ifndef CONFIG_NET_UDP_WRITE_BUFFERS
static inline void udp_poll_txnotify(FAR struct socket *psock)
{
FAR struct tcp_conn_s *conn = psock->conn;
FAR struct udp_conn_s *conn = psock->s_conn;
#ifdef CONFIG_NET_IPv4
#ifdef CONFIG_NET_IPv6
@ -320,12 +321,22 @@ int udp_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds)
else if ((fds->events & POLLOUT) != 0)
{
/* Check if the socket has been bound to a local address (might be
* INADDR_ANY or the IPv6 unspecified address! In that case the
* notification will fail)
*/
if (_SS_ISBOUND(psock->s_flags))
{
udp_poll_txnotify(psock);
}
#ifdef CONFIG_NET_UDP_BINDTODEVICE
/* Check if the socket has been bound to a device interface index via
* the UDP_BINDTODEVICE socket option.
*/
if (conn->boundto > 0)
else if (conn->boundto > 0)
{
/* Yes, find the device associated with the interface index */
@ -337,17 +348,7 @@ int udp_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds)
netdev_txnotify_dev(dev);
}
}
else
#endif
/* Check if the socket has been bound to a local address (might be
* INADDR_ANY or the IPv6 unspecified address! In that case the
* notification will fail)
*/
if (_SS_ISBOUND(psock->s_flags))
{
udp_poll_txnotify(psock);
}
}
#endif

View File

@ -158,7 +158,7 @@ static int16_t work_notifier_key(void)
{
int16_t key;
/* Loop until a unique key is generated */
/* Loop until a unique key is generated. Range 1-INT16_MAX. */
do
{
@ -273,6 +273,8 @@ int work_notifier_teardown(int key)
FAR struct work_notifier_entry_s *prev;
int ret;
DEBUGASSERT(key > 0 && key <= INT16_MAX);
/* Get exclusive access to the notifier data structures */
ret = nxsem_wait(&g_notifier_sem);