You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2020/11/28 06:03:58 UTC

[incubator-nuttx] 01/02: net/tcp: fallback to unthrottle pool to avoid deadlock

This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git

commit bf210560017b8df1201c02bcf1afee1fabaa37e8
Author: chao.an <an...@xiaomi.com>
AuthorDate: Fri Nov 27 09:50:38 2020 +0800

    net/tcp: fallback to unthrottle pool to avoid deadlock
    
    Add a fallback mechanism to ensure that there are still available
    iobs for an free connection, Guarantees all connections will have
    a minimum threshold iob to keep the connection not be hanged.
    
    Change-Id: I59bed98d135ccd1f16264b9ccacdd1b0d91261de
    Signed-off-by: chao.an <an...@xiaomi.com>
---
 net/sixlowpan/sixlowpan_tcpsend.c |  2 +-
 net/tcp/tcp.h                     |  6 ++++--
 net/tcp/tcp_callback.c            | 21 +++++++++++++++++----
 net/tcp/tcp_recvwindow.c          | 26 +++++++++++++++++---------
 net/tcp/tcp_send.c                |  2 +-
 5 files changed, 40 insertions(+), 17 deletions(-)

diff --git a/net/sixlowpan/sixlowpan_tcpsend.c b/net/sixlowpan/sixlowpan_tcpsend.c
index 81ba7b5..9f39865 100644
--- a/net/sixlowpan/sixlowpan_tcpsend.c
+++ b/net/sixlowpan/sixlowpan_tcpsend.c
@@ -256,7 +256,7 @@ static int sixlowpan_tcp_header(FAR struct tcp_conn_s *conn,
     {
       /* Update the TCP received window based on I/O buffer availability */
 
-      uint16_t recvwndo = tcp_get_recvwindow(dev);
+      uint16_t recvwndo = tcp_get_recvwindow(dev, conn);
 
       /* Set the TCP Window */
 
diff --git a/net/tcp/tcp.h b/net/tcp/tcp.h
index 044869f..902387a 100644
--- a/net/tcp/tcp.h
+++ b/net/tcp/tcp.h
@@ -1430,14 +1430,16 @@ int tcp_getsockopt(FAR struct socket *psock, int option,
  *   Calculate the TCP receive window for the specified device.
  *
  * Input Parameters:
- *   dev - The device whose TCP receive window will be updated.
+ *   dev  - The device whose TCP receive window will be updated.
+ *   conn - The TCP connection structure holding connection information.
  *
  * Returned Value:
  *   The value of the TCP receive window to use.
  *
  ****************************************************************************/
 
-uint16_t tcp_get_recvwindow(FAR struct net_driver_s *dev);
+uint16_t tcp_get_recvwindow(FAR struct net_driver_s *dev,
+                            FAR struct tcp_conn_s *conn);
 
 /****************************************************************************
  * Name: psock_tcp_cansend
diff --git a/net/tcp/tcp_callback.c b/net/tcp/tcp_callback.c
index ba2d4d7..2cd21aa 100644
--- a/net/tcp/tcp_callback.c
+++ b/net/tcp/tcp_callback.c
@@ -241,6 +241,7 @@ uint16_t tcp_datahandler(FAR struct tcp_conn_s *conn, FAR uint8_t *buffer,
                          uint16_t buflen)
 {
   FAR struct iob_s *iob;
+  bool throttled = true;
   int ret;
 
   /* Try to allocate on I/O buffer to start the chain without waiting (and
@@ -248,16 +249,28 @@ uint16_t tcp_datahandler(FAR struct tcp_conn_s *conn, FAR uint8_t *buffer,
    * packet.
    */
 
-  iob = iob_tryalloc(true, IOBUSER_NET_TCP_READAHEAD);
+  iob = iob_tryalloc(throttled, IOBUSER_NET_TCP_READAHEAD);
   if (iob == NULL)
     {
-      nerr("ERROR: Failed to create new I/O buffer chain\n");
-      return 0;
+#if CONFIG_IOB_THROTTLE > 0
+      if (IOB_QEMPTY(&conn->readahead))
+        {
+          /* Fallback out of the throttled entry */
+
+          throttled = false;
+          iob = iob_tryalloc(throttled, IOBUSER_NET_TCP_READAHEAD);
+        }
+#endif
+      if (iob == NULL)
+        {
+          nerr("ERROR: Failed to create new I/O buffer chain\n");
+          return 0;
+        }
     }
 
   /* Copy the new appdata into the I/O buffer chain (without waiting) */
 
-  ret = iob_trycopyin(iob, buffer, buflen, 0, true,
+  ret = iob_trycopyin(iob, buffer, buflen, 0, throttled,
                       IOBUSER_NET_TCP_READAHEAD);
   if (ret < 0)
     {
diff --git a/net/tcp/tcp_recvwindow.c b/net/tcp/tcp_recvwindow.c
index c6b2dea..9ab270d 100644
--- a/net/tcp/tcp_recvwindow.c
+++ b/net/tcp/tcp_recvwindow.c
@@ -70,7 +70,8 @@
  *
  ****************************************************************************/
 
-uint16_t tcp_get_recvwindow(FAR struct net_driver_s *dev)
+uint16_t tcp_get_recvwindow(FAR struct net_driver_s *dev,
+                            FAR struct tcp_conn_s *conn)
 {
   uint16_t iplen;
   uint16_t mss;
@@ -139,9 +140,9 @@ uint16_t tcp_get_recvwindow(FAR struct net_driver_s *dev)
       uint32_t rwnd;
 
       /* The optimal TCP window size is the amount of TCP data that we can
-       * currently buffer via TCP read-ahead buffering plus MSS for the
-       * device packet buffer.  This logic here assumes that all IOBs are
-       * available for TCP buffering.
+       * currently buffer via TCP read-ahead buffering for the device packet
+       * buffer.  This logic here assumes that all IOBs are available for
+       * TCP buffering.
        *
        * Assume that all of the available IOBs are can be used for buffering
        * on this connection.  Also assume that at least one chain is available
@@ -154,7 +155,7 @@ uint16_t tcp_get_recvwindow(FAR struct net_driver_s *dev)
        * buffering for this connection.
        */
 
-      rwnd = (niob_avail * CONFIG_IOB_BUFSIZE) + mss;
+      rwnd = (niob_avail * CONFIG_IOB_BUFSIZE);
       if (rwnd > UINT16_MAX)
         {
           rwnd = UINT16_MAX;
@@ -164,17 +165,24 @@ uint16_t tcp_get_recvwindow(FAR struct net_driver_s *dev)
 
       recvwndo = (uint16_t)rwnd;
     }
+  else if (IOB_QEMPTY(&conn->readahead))
+    {
+      /* Advertise maximum segment size for window edge if here is no
+       * available iobs on current "free" connection.
+       */
+
+      recvwndo = mss;
+    }
   else /* nqentry_avail == 0 || niob_avail == 0 */
     {
-      /* No IOB chains or noIOBs are available.  The only buffering
-       * available is within the packet buffer itself.  We can buffer no
-       * more than the MSS (unless we are very fast).
+      /* No IOB chains or noIOBs are available.
+       * Advertise the edge of window to zero.
        *
        * NOTE:  If no IOBs are available, then the next packet will be
        * lost if there is no listener on the connection.
        */
 
-      recvwndo = mss;
+      recvwndo = 0;
     }
 
   return recvwndo;
diff --git a/net/tcp/tcp_send.c b/net/tcp/tcp_send.c
index 882764c..ee82f00 100644
--- a/net/tcp/tcp_send.c
+++ b/net/tcp/tcp_send.c
@@ -360,7 +360,7 @@ static void tcp_sendcommon(FAR struct net_driver_s *dev,
     {
       /* Update the TCP received window based on I/O buffer availability */
 
-      uint16_t recvwndo = tcp_get_recvwindow(dev);
+      uint16_t recvwndo = tcp_get_recvwindow(dev, conn);
 
       /* Set the TCP Window */