mirror of
https://github.com/apache/nuttx.git
synced 2026-05-27 11:26:12 +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 */
|
/* 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 */
|
/* 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.
|
* Calculate the TCP receive window for the specified device.
|
||||||
*
|
*
|
||||||
* Input Parameters:
|
* 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:
|
* Returned Value:
|
||||||
* The value of the TCP receive window to use.
|
* 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
|
* 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)
|
uint16_t buflen)
|
||||||
{
|
{
|
||||||
FAR struct iob_s *iob;
|
FAR struct iob_s *iob;
|
||||||
|
bool throttled = true;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Try to allocate on I/O buffer to start the chain without waiting (and
|
/* 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.
|
* packet.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
iob = iob_tryalloc(true, IOBUSER_NET_TCP_READAHEAD);
|
iob = iob_tryalloc(throttled, IOBUSER_NET_TCP_READAHEAD);
|
||||||
if (iob == NULL)
|
if (iob == NULL)
|
||||||
{
|
{
|
||||||
nerr("ERROR: Failed to create new I/O buffer chain\n");
|
#if CONFIG_IOB_THROTTLE > 0
|
||||||
return 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) */
|
/* 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);
|
IOBUSER_NET_TCP_READAHEAD);
|
||||||
if (ret < 0)
|
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 iplen;
|
||||||
uint16_t mss;
|
uint16_t mss;
|
||||||
@@ -139,9 +140,9 @@ uint16_t tcp_get_recvwindow(FAR struct net_driver_s *dev)
|
|||||||
uint32_t rwnd;
|
uint32_t rwnd;
|
||||||
|
|
||||||
/* The optimal TCP window size is the amount of TCP data that we can
|
/* 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
|
* currently buffer via TCP read-ahead buffering for the device packet
|
||||||
* device packet buffer. This logic here assumes that all IOBs are
|
* buffer. This logic here assumes that all IOBs are available for
|
||||||
* available for TCP buffering.
|
* TCP buffering.
|
||||||
*
|
*
|
||||||
* Assume that all of the available IOBs are can be used for 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
|
* 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.
|
* buffering for this connection.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
rwnd = (niob_avail * CONFIG_IOB_BUFSIZE) + mss;
|
rwnd = (niob_avail * CONFIG_IOB_BUFSIZE);
|
||||||
if (rwnd > UINT16_MAX)
|
if (rwnd > UINT16_MAX)
|
||||||
{
|
{
|
||||||
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;
|
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 */
|
else /* nqentry_avail == 0 || niob_avail == 0 */
|
||||||
{
|
{
|
||||||
/* No IOB chains or noIOBs are available. The only buffering
|
/* No IOB chains or noIOBs are available.
|
||||||
* available is within the packet buffer itself. We can buffer no
|
* Advertise the edge of window to zero.
|
||||||
* more than the MSS (unless we are very fast).
|
|
||||||
*
|
*
|
||||||
* NOTE: If no IOBs are available, then the next packet will be
|
* NOTE: If no IOBs are available, then the next packet will be
|
||||||
* lost if there is no listener on the connection.
|
* lost if there is no listener on the connection.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
recvwndo = mss;
|
recvwndo = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return recvwndo;
|
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 */
|
/* 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 */
|
/* Set the TCP Window */
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user