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 */