net/tcp: wave hands on background
The time consuming of tcp waving hands(close(2)) will be affected by network jitter, especially the wireless device cannot receive the last-ack under worst environment, in this change we move the tcp close callback into background and invoke the resource free from workqueue, which will avoid the user application from being blocked for a long time and unable to return in the call of close Signed-off-by: chao.an <anchao@xiaomi.com>
This commit is contained in:
parent
6bd36d64e3
commit
0636c17a63
@ -304,6 +304,11 @@ struct tcp_conn_s
|
||||
FAR struct devif_callback_s *connevents;
|
||||
FAR struct devif_callback_s *connevents_tail;
|
||||
|
||||
/* Reference to TCP close callback instance */
|
||||
|
||||
FAR struct devif_callback_s *clscb;
|
||||
struct work_s clswork;
|
||||
|
||||
#if defined(CONFIG_NET_TCP_WRITE_BUFFERS)
|
||||
/* Callback instance for TCP send() */
|
||||
|
||||
|
@ -39,22 +39,30 @@
|
||||
#include "tcp/tcp.h"
|
||||
#include "socket/socket.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
struct tcp_close_s
|
||||
{
|
||||
FAR struct tcp_conn_s *cl_conn; /* Needed to handle loss of connection */
|
||||
FAR struct devif_callback_s *cl_cb; /* Reference to TCP callback instance */
|
||||
sem_t cl_sem; /* Signals disconnect completion */
|
||||
int cl_result; /* The result of the close */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: tcp_close_work
|
||||
****************************************************************************/
|
||||
|
||||
static void tcp_close_work(FAR void *param)
|
||||
{
|
||||
FAR struct tcp_conn_s *conn = (FAR struct tcp_conn_s *)param;
|
||||
|
||||
net_lock();
|
||||
|
||||
tcp_callback_free(conn, conn->clscb);
|
||||
|
||||
/* Stop the network monitor for all sockets */
|
||||
|
||||
tcp_stop_monitor(conn, TCP_CLOSE);
|
||||
tcp_free(conn);
|
||||
|
||||
net_unlock();
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: tcp_close_eventhandler
|
||||
****************************************************************************/
|
||||
@ -63,10 +71,7 @@ static uint16_t tcp_close_eventhandler(FAR struct net_driver_s *dev,
|
||||
FAR void *pvconn, FAR void *pvpriv,
|
||||
uint16_t flags)
|
||||
{
|
||||
FAR struct tcp_close_s *pstate = (FAR struct tcp_close_s *)pvpriv;
|
||||
FAR struct tcp_conn_s *conn = pstate->cl_conn;
|
||||
|
||||
DEBUGASSERT(pstate != NULL);
|
||||
FAR struct tcp_conn_s *conn = pvpriv;
|
||||
|
||||
ninfo("flags: %04x\n", flags);
|
||||
|
||||
@ -106,15 +111,6 @@ static uint16_t tcp_close_eventhandler(FAR struct net_driver_s *dev,
|
||||
* NETWORK_DOWN event is processed further.
|
||||
*/
|
||||
|
||||
if ((flags & NETDEV_DOWN) != 0)
|
||||
{
|
||||
pstate->cl_result = -ENODEV;
|
||||
}
|
||||
else
|
||||
{
|
||||
pstate->cl_result = OK;
|
||||
}
|
||||
|
||||
goto end_wait;
|
||||
}
|
||||
|
||||
@ -182,12 +178,14 @@ static uint16_t tcp_close_eventhandler(FAR struct net_driver_s *dev,
|
||||
return flags;
|
||||
|
||||
end_wait:
|
||||
pstate->cl_cb->flags = 0;
|
||||
pstate->cl_cb->priv = NULL;
|
||||
pstate->cl_cb->event = NULL;
|
||||
nxsem_post(&pstate->cl_sem);
|
||||
conn->clscb->flags = 0;
|
||||
conn->clscb->priv = NULL;
|
||||
conn->clscb->event = NULL;
|
||||
|
||||
/* Free network resources */
|
||||
|
||||
work_queue(LPWORK, &conn->clswork, tcp_close_work, conn, 0);
|
||||
|
||||
ninfo("Resuming\n");
|
||||
return flags;
|
||||
}
|
||||
|
||||
@ -257,7 +255,6 @@ static inline void tcp_close_txnotify(FAR struct socket *psock,
|
||||
|
||||
static inline int tcp_close_disconnect(FAR struct socket *psock)
|
||||
{
|
||||
struct tcp_close_s state;
|
||||
FAR struct tcp_conn_s *conn;
|
||||
int ret = OK;
|
||||
|
||||
@ -307,58 +304,28 @@ static inline int tcp_close_disconnect(FAR struct socket *psock)
|
||||
|
||||
if ((conn->tcpstateflags == TCP_ESTABLISHED ||
|
||||
conn->tcpstateflags == TCP_LAST_ACK) &&
|
||||
(state.cl_cb = tcp_callback_alloc(conn)) != NULL)
|
||||
(conn->clscb = tcp_callback_alloc(conn)) != NULL)
|
||||
{
|
||||
/* Set up to receive TCP data event callbacks */
|
||||
|
||||
state.cl_cb->flags = (TCP_NEWDATA | TCP_POLL | TCP_DISCONN_EVENTS);
|
||||
state.cl_cb->event = tcp_close_eventhandler;
|
||||
|
||||
/* A non-NULL value of the priv field means that lingering is
|
||||
* enabled.
|
||||
*/
|
||||
|
||||
state.cl_cb->priv = (FAR void *)&state;
|
||||
|
||||
/* Set up for the lingering wait */
|
||||
|
||||
state.cl_conn = conn;
|
||||
state.cl_result = -EBUSY;
|
||||
|
||||
/* This semaphore is used for signaling and, hence, should not have
|
||||
* priority inheritance enabled.
|
||||
*/
|
||||
|
||||
nxsem_init(&state.cl_sem, 0, 0);
|
||||
nxsem_set_protocol(&state.cl_sem, SEM_PRIO_NONE);
|
||||
conn->clscb->flags = (TCP_NEWDATA | TCP_POLL | TCP_DISCONN_EVENTS);
|
||||
conn->clscb->event = tcp_close_eventhandler;
|
||||
conn->clscb->priv = conn;
|
||||
|
||||
/* Notify the device driver of the availability of TX data */
|
||||
|
||||
tcp_close_txnotify(psock, conn);
|
||||
|
||||
/* Wait for the disconnect event */
|
||||
|
||||
net_lockedwait(&state.cl_sem);
|
||||
|
||||
/* We are now disconnected */
|
||||
|
||||
nxsem_destroy(&state.cl_sem);
|
||||
tcp_callback_free(conn, state.cl_cb);
|
||||
|
||||
/* Free the connection
|
||||
* No more references on the connection
|
||||
*/
|
||||
|
||||
conn->crefs = 0;
|
||||
|
||||
/* Get the result of the close */
|
||||
|
||||
ret = state.cl_result;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Stop the network monitor for all sockets */
|
||||
|
||||
/* Free network resources */
|
||||
tcp_stop_monitor(conn, TCP_CLOSE);
|
||||
|
||||
tcp_free(conn);
|
||||
/* Free network resources */
|
||||
|
||||
tcp_free(conn);
|
||||
}
|
||||
|
||||
net_unlock();
|
||||
return ret;
|
||||
@ -385,7 +352,6 @@ static inline int tcp_close_disconnect(FAR struct socket *psock)
|
||||
int tcp_close(FAR struct socket *psock)
|
||||
{
|
||||
FAR struct tcp_conn_s *conn = psock->s_conn;
|
||||
int ret;
|
||||
|
||||
/* Perform the disconnection now */
|
||||
|
||||
@ -394,21 +360,7 @@ int tcp_close(FAR struct socket *psock)
|
||||
|
||||
/* Break any current connections and close the socket */
|
||||
|
||||
ret = tcp_close_disconnect(psock);
|
||||
if (ret < 0)
|
||||
{
|
||||
/* This would normally occur only if there is a timeout
|
||||
* from a lingering close.
|
||||
*/
|
||||
|
||||
nerr("ERROR: tcp_close_disconnect failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Stop the network monitor for all sockets */
|
||||
|
||||
tcp_stop_monitor(conn, TCP_CLOSE);
|
||||
return OK;
|
||||
return tcp_close_disconnect(psock);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_NET_TCP */
|
||||
|
Loading…
Reference in New Issue
Block a user