net/tcp: Write buffering logic should not wait for a free buffer if the socket was opened non-blocking. Also, rename the TCP write buffering macros from WRB_* to TCPWB_* to make room in the namespace for write buffering with other protocols.

This commit is contained in:
Gregory Nutt
2018-01-22 11:11:23 -06:00
parent a8b6be4aaf
commit 12d7125b75
4 changed files with 98 additions and 82 deletions
+20 -17
View File
@@ -1,7 +1,7 @@
/****************************************************************************
* net/tcp/tcp.h
*
* Copyright (C) 2014-2016 Gregory Nutt. All rights reserved.
* Copyright (C) 2014-2016, 2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@@ -77,23 +77,26 @@
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
/* TCP write buffer access macros */
# define WRB_SEQNO(wrb) ((wrb)->wb_seqno)
# define WRB_PKTLEN(wrb) ((wrb)->wb_iob->io_pktlen)
# define WRB_SENT(wrb) ((wrb)->wb_sent)
# define WRB_NRTX(wrb) ((wrb)->wb_nrtx)
# define WRB_IOB(wrb) ((wrb)->wb_iob)
# define WRB_COPYOUT(wrb,dest,n) (iob_copyout(dest,(wrb)->wb_iob,(n),0))
# define WRB_COPYIN(wrb,src,n) (iob_copyin((wrb)->wb_iob,src,(n),0,false))
# define TCPWB_SEQNO(wrb) ((wrb)->wb_seqno)
# define TCPWB_PKTLEN(wrb) ((wrb)->wb_iob->io_pktlen)
# define TCPWB_SENT(wrb) ((wrb)->wb_sent)
# define TCPWB_NRTX(wrb) ((wrb)->wb_nrtx)
# define TCPWB_IOB(wrb) ((wrb)->wb_iob)
# define TCPWB_COPYOUT(wrb,dest,n) (iob_copyout(dest,(wrb)->wb_iob,(n),0))
# define TCPWB_COPYIN(wrb,src,n) \
(iob_copyin((wrb)->wb_iob,src,(n),0,false))
# define TCPWB_TRYCOPYIN(wrb,src,n) \
(iob_trycopyin((wrb)->wb_iob,src,(n),0,false))
# define WRB_TRIM(wrb,n) \
do { (wrb)->wb_iob = iob_trimhead((wrb)->wb_iob,(n)); } while (0)
# define TCPWB_TRIM(wrb,n) \
do { (wrb)->wb_iob = iob_trimhead((wrb)->wb_iob,(n)); } while (0)
#ifdef CONFIG_DEBUG_FEATURES
# define WRB_DUMP(msg,wrb,len,offset) \
# define TCPWB_DUMP(msg,wrb,len,offset) \
tcp_wrbuffer_dump(msg,wrb,len,offset)
#else
# define WRB_DUMP(msg,wrb,len,offset)
#endif
# else
# define TCPWB_DUMP(msg,wrb,len,offset)
# endif
#endif
/****************************************************************************
@@ -438,7 +441,7 @@ int tcp_local_ipv6_device(FAR struct tcp_conn_s *conn);
*
* Description:
* Select the network driver to use with the IPv6 TCP transaction based
* on the remotely conected IPv6 address
* on the remotely connected IPv6 address
*
* Input Parameters:
* conn - TCP connection structure. The remotely connected address, raddr,
@@ -558,7 +561,7 @@ int tcp_start_monitor(FAR struct socket *psock);
*
* Description:
* Stop monitoring TCP connection changes for a sockets associated with
* a given TCP connection stucture.
* a given TCP connection structure.
*
* Input Parameters:
* conn - The TCP connection of interest
@@ -1282,7 +1285,7 @@ ssize_t psock_tcp_send(FAR struct socket *psock, FAR const void *buf,
*
* Returned Value:
* OK
* At least one byte of data could be succesfully written.
* At least one byte of data could be successfully written.
* -EWOULDBLOCK
* There is no room in the output buffer.
* -EBADF
+65 -52
View File
@@ -1,7 +1,7 @@
/****************************************************************************
* net/tcp/tcp_send_buffered.c
*
* Copyright (C) 2007-2014, 2016-2017 Gregory Nutt. All rights reserved.
* Copyright (C) 2007-2014, 2016-2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
* Jason Jiang <jasonj@live.cn>
*
@@ -98,8 +98,8 @@
# define BUF_DUMP(msg,buf,len) lib_dumpbuffer(msg,buf,len)
#else
# define BUF_DUMP(msg,buf,len)
# undef WRB_DUMP
# define WRB_DUMP(msg,wrb,len,offset)
# undef TCPWB_DUMP
# define TCPWB_DUMP(msg,wrb,len,offset)
#endif
/****************************************************************************
@@ -135,7 +135,7 @@ static void psock_insert_segment(FAR struct tcp_wrbuffer_s *wrb,
for (itr = sq_peek(q); itr; itr = sq_next(itr))
{
FAR struct tcp_wrbuffer_s *wrb0 = (FAR struct tcp_wrbuffer_s *)itr;
if (WRB_SEQNO(wrb0) < WRB_SEQNO(wrb))
if (TCPWB_SEQNO(wrb0) < TCPWB_SEQNO(wrb))
{
insert = itr;
}
@@ -417,13 +417,14 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
* the write buffer has been ACKed.
*/
if (ackno > WRB_SEQNO(wrb))
if (ackno > TCPWB_SEQNO(wrb))
{
/* Get the sequence number at the end of the data */
lastseq = WRB_SEQNO(wrb) + WRB_PKTLEN(wrb);
lastseq = TCPWB_SEQNO(wrb) + TCPWB_PKTLEN(wrb);
ninfo("ACK: wrb=%p seqno=%u lastseq=%u pktlen=%u ackno=%u\n",
wrb, WRB_SEQNO(wrb), lastseq, WRB_PKTLEN(wrb), ackno);
wrb, TCPWB_SEQNO(wrb), lastseq, TCPWB_PKTLEN(wrb),
ackno);
/* Has the entire buffer been ACKed? */
@@ -449,24 +450,24 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
* buffers in the chain.
*/
trimlen = ackno - WRB_SEQNO(wrb);
if (trimlen > WRB_SENT(wrb))
trimlen = ackno - TCPWB_SEQNO(wrb);
if (trimlen > TCPWB_SENT(wrb))
{
/* More data has been ACKed then we have sent? */
trimlen = WRB_SENT(wrb);
trimlen = TCPWB_SENT(wrb);
}
ninfo("ACK: wrb=%p trim %u bytes\n", wrb, trimlen);
WRB_TRIM(wrb, trimlen);
WRB_SEQNO(wrb) = ackno;
WRB_SENT(wrb) -= trimlen;
TCPWB_TRIM(wrb, trimlen);
TCPWB_SEQNO(wrb) = ackno;
TCPWB_SENT(wrb) -= trimlen;
/* Set the new sequence number for what remains */
ninfo("ACK: wrb=%p seqno=%u pktlen=%u\n",
wrb, WRB_SEQNO(wrb), WRB_PKTLEN(wrb));
wrb, TCPWB_SEQNO(wrb), TCPWB_PKTLEN(wrb));
}
}
}
@@ -477,31 +478,31 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
*/
wrb = (FAR struct tcp_wrbuffer_s *)sq_peek(&conn->write_q);
if (wrb && WRB_SENT(wrb) > 0 && ackno > WRB_SEQNO(wrb))
if (wrb && TCPWB_SENT(wrb) > 0 && ackno > TCPWB_SEQNO(wrb))
{
uint32_t nacked;
/* Number of bytes that were ACKed */
nacked = ackno - WRB_SEQNO(wrb);
if (nacked > WRB_SENT(wrb))
nacked = ackno - TCPWB_SEQNO(wrb);
if (nacked > TCPWB_SENT(wrb))
{
/* More data has been ACKed then we have sent? ASSERT? */
nacked = WRB_SENT(wrb);
nacked = TCPWB_SENT(wrb);
}
ninfo("ACK: wrb=%p seqno=%u nacked=%u sent=%u ackno=%u\n",
wrb, WRB_SEQNO(wrb), nacked, WRB_SENT(wrb), ackno);
wrb, TCPWB_SEQNO(wrb), nacked, TCPWB_SENT(wrb), ackno);
/* Trim the ACKed bytes from the beginning of the write buffer. */
WRB_TRIM(wrb, nacked);
WRB_SEQNO(wrb) = ackno;
WRB_SENT(wrb) -= nacked;
TCPWB_TRIM(wrb, nacked);
TCPWB_SEQNO(wrb) = ackno;
TCPWB_SENT(wrb) -= nacked;
ninfo("ACK: wrb=%p seqno=%u pktlen=%u sent=%u\n",
wrb, WRB_SEQNO(wrb), WRB_PKTLEN(wrb), WRB_SENT(wrb));
wrb, TCPWB_SEQNO(wrb), TCPWB_PKTLEN(wrb), TCPWB_SENT(wrb));
}
}
@@ -543,16 +544,16 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
*/
wrb = (FAR struct tcp_wrbuffer_s *)sq_peek(&conn->write_q);
ninfo("REXMIT: wrb=%p sent=%u\n", wrb, wrb ? WRB_SENT(wrb) : 0);
ninfo("REXMIT: wrb=%p sent=%u\n", wrb, wrb ? TCPWB_SENT(wrb) : 0);
if (wrb != NULL && WRB_SENT(wrb) > 0)
if (wrb != NULL && TCPWB_SENT(wrb) > 0)
{
FAR struct tcp_wrbuffer_s *tmp;
uint16_t sent;
/* Yes.. Reset the number of bytes sent sent from the write buffer */
sent = WRB_SENT(wrb);
sent = TCPWB_SENT(wrb);
if (conn->unacked > sent)
{
conn->unacked -= sent;
@@ -571,16 +572,16 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
conn->sent = 0;
}
WRB_SENT(wrb) = 0;
TCPWB_SENT(wrb) = 0;
ninfo("REXMIT: wrb=%p sent=%u, conn unacked=%d sent=%d\n",
wrb, WRB_SENT(wrb), conn->unacked, conn->sent);
wrb, TCPWB_SENT(wrb), conn->unacked, conn->sent);
/* Increment the retransmit count on this write buffer. */
if (++WRB_NRTX(wrb) >= TCP_MAXRTX)
if (++TCPWB_NRTX(wrb) >= TCP_MAXRTX)
{
nwarn("WARNING: Expiring wrb=%p nrtx=%u\n",
wrb, WRB_NRTX(wrb));
wrb, TCPWB_NRTX(wrb));
/* The maximum retry count as been exhausted. Remove the write
* buffer at the head of the queue.
@@ -618,7 +619,7 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
/* Reset the number of bytes sent sent from the write buffer */
sent = WRB_SENT(wrb);
sent = TCPWB_SENT(wrb);
if (conn->unacked > sent)
{
conn->unacked -= sent;
@@ -637,16 +638,16 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
conn->sent = 0;
}
WRB_SENT(wrb) = 0;
TCPWB_SENT(wrb) = 0;
ninfo("REXMIT: wrb=%p sent=%u, conn unacked=%d sent=%d\n",
wrb, WRB_SENT(wrb), conn->unacked, conn->sent);
wrb, TCPWB_SENT(wrb), conn->unacked, conn->sent);
/* Free any write buffers that have exceed the retry count */
if (++WRB_NRTX(wrb) >= TCP_MAXRTX)
if (++TCPWB_NRTX(wrb) >= TCP_MAXRTX)
{
nwarn("WARNING: Expiring wrb=%p nrtx=%u\n",
wrb, WRB_NRTX(wrb));
wrb, TCPWB_NRTX(wrb));
/* Return the write buffer to the free list */
@@ -671,7 +672,7 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
* is pulled from the write_q again.
*/
ninfo("REXMIT: Moving wrb=%p nrtx=%u\n", wrb, WRB_NRTX(wrb));
ninfo("REXMIT: Moving wrb=%p nrtx=%u\n", wrb, TCPWB_NRTX(wrb));
psock_insert_segment(wrb, &conn->write_q);
}
@@ -726,7 +727,7 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
* window size.
*/
sndlen = WRB_PKTLEN(wrb) - WRB_SENT(wrb);
sndlen = TCPWB_PKTLEN(wrb) - TCPWB_SENT(wrb);
if (sndlen > conn->mss)
{
sndlen = conn->mss;
@@ -738,16 +739,16 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
}
ninfo("SEND: wrb=%p pktlen=%u sent=%u sndlen=%u\n",
wrb, WRB_PKTLEN(wrb), WRB_SENT(wrb), sndlen);
wrb, TCPWB_PKTLEN(wrb), TCPWB_SENT(wrb), sndlen);
/* Set the sequence number for this segment. If we are
* retransmitting, then the sequence number will already
* be set for this write buffer.
*/
if (WRB_SEQNO(wrb) == (unsigned)-1)
if (TCPWB_SEQNO(wrb) == (unsigned)-1)
{
WRB_SEQNO(wrb) = conn->isn + conn->sent;
TCPWB_SEQNO(wrb) = conn->isn + conn->sent;
}
/* The TCP stack updates sndseq on receipt of ACK *before*
@@ -757,7 +758,7 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
* before the packet is sent.
*/
tcp_setsequence(conn->sndseq, WRB_SEQNO(wrb) + WRB_SENT(wrb));
tcp_setsequence(conn->sndseq, TCPWB_SEQNO(wrb) + TCPWB_SENT(wrb));
#ifdef NEED_IPDOMAIN_SUPPORT
/* If both IPv4 and IPv6 support are enabled, then we will need to
@@ -773,7 +774,7 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
* won't actually happen until the polling cycle completes).
*/
devif_iob_send(dev, WRB_IOB(wrb), sndlen, WRB_SENT(wrb));
devif_iob_send(dev, TCPWB_IOB(wrb), sndlen, TCPWB_SENT(wrb));
/* Remember how much data we send out now so that we know
* when everything has been acknowledged. Just increment
@@ -795,21 +796,21 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
}
ninfo("SEND: wrb=%p nrtx=%u unacked=%u sent=%u\n",
wrb, WRB_NRTX(wrb), conn->unacked, conn->sent);
wrb, TCPWB_NRTX(wrb), conn->unacked, conn->sent);
/* Increment the count of bytes sent from this write buffer */
WRB_SENT(wrb) += sndlen;
TCPWB_SENT(wrb) += sndlen;
ninfo("SEND: wrb=%p sent=%u pktlen=%u\n",
wrb, WRB_SENT(wrb), WRB_PKTLEN(wrb));
wrb, TCPWB_SENT(wrb), TCPWB_PKTLEN(wrb));
/* Remove the write buffer from the write queue if the
* last of the data has been sent from the buffer.
*/
DEBUGASSERT(WRB_SENT(wrb) <= WRB_PKTLEN(wrb));
if (WRB_SENT(wrb) >= WRB_PKTLEN(wrb))
DEBUGASSERT(TCPWB_SENT(wrb) <= TCPWB_PKTLEN(wrb));
if (TCPWB_SENT(wrb) >= TCPWB_PKTLEN(wrb))
{
FAR struct tcp_wrbuffer_s *tmp;
@@ -1060,13 +1061,25 @@ ssize_t psock_tcp_send(FAR struct socket *psock, FAR const void *buf,
/* Initialize the write buffer */
WRB_SEQNO(wrb) = (unsigned)-1;
WRB_NRTX(wrb) = 0;
result = WRB_COPYIN(wrb, (FAR uint8_t *)buf, len);
TCPWB_SEQNO(wrb) = (unsigned)-1;
TCPWB_NRTX(wrb) = 0;
/* Copy the user data into the write buffer. We cannot wait for
* buffer space if the socket was opened non-blocking.
*/
if (_SS_ISNONBLOCK(psock->s_flags))
{
result = TCPWB_TRYCOPYIN(wrb, (FAR uint8_t *)buf, len);
}
else
{
result = TCPWB_COPYIN(wrb, (FAR uint8_t *)buf, len);
}
/* Dump I/O buffer chain */
WRB_DUMP("I/O buffer chain", wrb, WRB_PKTLEN(wrb), 0);
TCPWB_DUMP("I/O buffer chain", wrb, TCPWB_PKTLEN(wrb), 0);
/* psock_send_eventhandler() will send data in FIFO order from the
* conn->write_q
@@ -1074,7 +1087,7 @@ ssize_t psock_tcp_send(FAR struct socket *psock, FAR const void *buf,
sq_addlast(&wrb->wb_node, &conn->write_q);
ninfo("Queued WRB=%p pktlen=%u write_q(%p,%p)\n",
wrb, WRB_PKTLEN(wrb),
wrb, TCPWB_PKTLEN(wrb),
conn->write_q.head, conn->write_q.tail);
/* Notify the device driver of the availability of TX data */
+3 -3
View File
@@ -1,7 +1,7 @@
/****************************************************************************
* net/tcp/tcp_wrbuffer_dump.c
*
* Copyright (C) 2014 Gregory Nutt. All rights reserved.
* Copyright (C) 2014, 2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@@ -64,8 +64,8 @@ void tcp_wrbuffer_dump(FAR const char *msg, FAR struct tcp_wrbuffer_s *wrb,
unsigned int len, unsigned int offset)
{
syslog(LOG_DEBUG, "%s: wrb=%p segno=%d sent=%d nrtx=%d\n",
msg, wrb, WRB_SEQNO(wrb), WRB_SENT(wrb), WRB_NRTX(wrb));
iob_dump("I/O Buffer Chain", WRB_IOB(wrb), len, offset);
msg, wrb, TCPWB_SEQNO(wrb), TCPWB_SENT(wrb), TCPWB_NRTX(wrb));
iob_dump("I/O Buffer Chain", TCPWB_IOB(wrb), len, offset);
}
#endif /* CONFIG_DEBUG_FEATURES */