This is an automated email from the ASF dual-hosted git repository.

pkarashchenko pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new 0636c17a63 net/tcp: wave hands on background
0636c17a63 is described below

commit 0636c17a63caf9a8f04b13fcf2cc922e7d26555c
Author: chao.an <anc...@xiaomi.com>
AuthorDate: Thu Jun 9 17:23:26 2022 +0800

    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 <anc...@xiaomi.com>
---
 net/tcp/tcp.h       |   5 +++
 net/tcp/tcp_close.c | 124 ++++++++++++++++------------------------------------
 2 files changed, 43 insertions(+), 86 deletions(-)

diff --git a/net/tcp/tcp.h b/net/tcp/tcp.h
index dd57ed947c..c11550d742 100644
--- a/net/tcp/tcp.h
+++ b/net/tcp/tcp.h
@@ -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() */
 
diff --git a/net/tcp/tcp_close.c b/net/tcp/tcp_close.c
index 43bab9a10c..b3a81a80ce 100644
--- a/net/tcp/tcp_close.c
+++ b/net/tcp/tcp_close.c
@@ -40,21 +40,29 @@
 #include "socket/socket.h"
 
 /****************************************************************************
- * Private Types
+ * Private Functions
  ****************************************************************************/
 
-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,59 +304,29 @@ 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);
+    }
+  else
+    {
+      /* Stop the network monitor for all sockets */
 
-      /* 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;
+      tcp_stop_monitor(conn, TCP_CLOSE);
 
-      /* Get the result of the close */
+      /* Free network resources */
 
-      ret = state.cl_result;
+      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 */

Reply via email to