net/tcp: Extended support for sending to non-blocking tcp sockets.

This commit is contained in:
Pelle Windestam 2018-04-20 07:37:51 -06:00 committed by Gregory Nutt
parent 161fb98b11
commit 303e6499bd
3 changed files with 119 additions and 5 deletions

View File

@ -1416,6 +1416,25 @@ void tcp_wrbuffer_initialize(void);
struct tcp_wrbuffer_s;
FAR struct tcp_wrbuffer_s *tcp_wrbuffer_alloc(void);
/****************************************************************************
* Name: tcp_wrbuffer_tryalloc
*
* Description:
* Try to allocate a TCP write buffer by taking a pre-allocated buffer from
* the free list. This function is called from TCP logic when a buffer
* of TCP data is about to be sent if the socket is non-blocking. Returns
* immediately if allocation fails.
*
* Input parameters:
* None
*
* Assumptions:
* Called from user logic with the network locked.
*
****************************************************************************/
FAR struct tcp_wrbuffer_s *tcp_wrbuffer_tryalloc(void);
#endif /* CONFIG_NET_TCP_WRITE_BUFFERS */
/****************************************************************************

View File

@ -1086,13 +1086,21 @@ ssize_t psock_tcp_send(FAR struct socket *psock, FAR const void *buf,
*/
net_lock();
if (_SS_ISNONBLOCK(psock->s_flags))
{
wrb = tcp_wrbuffer_tryalloc();
}
else
{
wrb = tcp_wrbuffer_alloc();
if (!wrb)
}
if (wrb == NULL)
{
/* A buffer allocation error occurred */
nerr("ERROR: Failed to allocate write buffer\n");
ret = -ENOMEM;
ret = _SS_ISNONBLOCK(psock->s_flags) ? -EAGAIN : -ENOMEM;
goto errout_with_lock;
}
@ -1110,7 +1118,7 @@ ssize_t psock_tcp_send(FAR struct socket *psock, FAR const void *buf,
/* A buffer allocation error occurred */
nerr("ERROR: Failed to allocate callback\n");
ret = -ENOMEM;
ret = _SS_ISNONBLOCK(psock->s_flags) ? -EAGAIN : -ENOMEM;
goto errout_with_wrb;
}
@ -1132,7 +1140,33 @@ ssize_t psock_tcp_send(FAR struct socket *psock, FAR const void *buf,
if (_SS_ISNONBLOCK(psock->s_flags))
{
/* The return value from TCP_WBTRYCOPYIN is either OK or
* -ENOMEM if less than the entire data chunk could be allocated.
* If -ENOMEM is returned, check if at least a part of the data
* chunk was allocated. If more than zero bytes were sent
* we return that number and let the caller deal with sending the
* remaining data.
*/
result = TCP_WBTRYCOPYIN(wrb, (FAR uint8_t *)buf, len);
if (result == -ENOMEM)
{
if (TCP_WBPKTLEN(wrb) > 0)
{
ninfo("INFO: Allocated part of the requested data\n");
result = TCP_WBPKTLEN(wrb);
}
else
{
nerr("ERROR: Failed to add data to the I/O buffer chain\n");
ret = -EWOULDBLOCK;
goto errout_with_wrb;
}
}
else
{
result = len;
}
}
else
{

View File

@ -1,7 +1,8 @@
/****************************************************************************
* net/tcp/tcp_wrbuffer.c
*
* Copyright (C) 2007-2009, 2013-2014 Gregory Nutt. All rights reserved.
* Copyright (C) 2007-2009, 2013-2014, 2018 Gregory Nutt. All rights
* reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
* Jason Jiang <jasonj@live.cn>
*
@ -169,6 +170,66 @@ FAR struct tcp_wrbuffer_s *tcp_wrbuffer_alloc(void)
return wrb;
}
/****************************************************************************
* Name: tcp_wrbuffer_tryalloc
*
* Description:
* Try to allocate a TCP write buffer by taking a pre-allocated buffer from
* the free list. This function is called from TCP logic when a buffer
* of TCP data is about to be sent on a non-blocking socket. Returns
* immediately if the allocation failed.
*
* Input parameters:
* None
*
* Assumptions:
* Called from user logic with the network locked. Will return if no buffer
* is available.
*
****************************************************************************/
FAR struct tcp_wrbuffer_s *tcp_wrbuffer_tryalloc(void)
{
FAR struct tcp_wrbuffer_s *wrb;
/* We need to allocate two things: (1) A write buffer structure and (2)
* at least one I/O buffer to start the chain.
*
* Allocate the write buffer structure first then the IOBG. In order to
* avoid deadlocks, we will need to free the IOB first, then the write
* buffer
*/
if (tcp_wrbuffer_test() == OK)
{
DEBUGVERIFY(net_lockedwait(&g_wrbuffer.sem));
}
else
{
return NULL;
}
/* Now, we are guaranteed to have a write buffer structure reserved
* for us in the free list.
*/
wrb = (FAR struct tcp_wrbuffer_s *)sq_remfirst(&g_wrbuffer.freebuffers);
DEBUGASSERT(wrb);
memset(wrb, 0, sizeof(struct tcp_wrbuffer_s));
/* Now get the first I/O buffer for the write buffer structure */
wrb->wb_iob = iob_tryalloc(false);
if (!wrb->wb_iob)
{
nerr("ERROR: Failed to allocate I/O buffer\n");
tcp_wrbuffer_release(wrb);
return NULL;
}
return wrb;
}
/****************************************************************************
* Name: tcp_wrbuffer_release
*