mirror of
https://github.com/apache/nuttx.git
synced 2026-05-22 13:52:22 +08:00
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 <anchao@xiaomi.com>
This commit is contained in:
@@ -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 */
|
||||
|
||||
|
||||
+4
-2
@@ -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
|
||||
|
||||
+17
-4
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
+1
-1
@@ -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 */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user