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 <anc...@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 <anc...@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 */