net/tcp: Extended support for sending to non-blocking tcp sockets.
This commit is contained in:
parent
161fb98b11
commit
303e6499bd
@ -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 */
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user