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

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


The following commit(s) were added to refs/heads/master by this push:
     new 8b9c9aeeb0d drivers/rpmsg/rpmsg_port_uart: serialize the connect 
handshake
8b9c9aeeb0d is described below

commit 8b9c9aeeb0d49102f8c315088a08b8afe749ff31
Author: Bowen Wang <[email protected]>
AuthorDate: Thu Jul 16 19:37:52 2026 +0800

    drivers/rpmsg/rpmsg_port_uart: serialize the connect handshake
    
    The tx thread reads EVT_CONNED and sends CONNREQ without a lock, while
    the rx thread sets EVT_CONNED and replies CONNACK. A stale read lets
    the tx thread send CONNREQ after CONNACK has gone out:
    
          tx thread             rx thread (process_rx_conn)
     t0   read EVT_CONNED==0
                                <-- CONNREQ from peer
     t1                         set EVT_CONNED
                                send CONNACK  --> peer registers (#1)
     t2   send CONNREQ (stale)  --------------> peer takes it as a
                                                restart: unreg + reg (#2)
    
    Take a conn_lock around the tx startup check-and-send and around the
    EVT_CONNED update in rpmsg_port_uart_process_rx_conn(), so only one
    side starts the handshake and the peer registers once. The lock is not
    held across rpmsg_port_register()/unregister(): they can run the rx
    worker again on the same thread when no tx buffer is free.
    
    Signed-off-by: Bowen Wang <[email protected]>
---
 drivers/rpmsg/rpmsg_port_uart.c | 29 +++++++++++++++++++++++++++--
 1 file changed, 27 insertions(+), 2 deletions(-)

diff --git a/drivers/rpmsg/rpmsg_port_uart.c b/drivers/rpmsg/rpmsg_port_uart.c
index f6e03fbc509..92ef98d2ac1 100644
--- a/drivers/rpmsg/rpmsg_port_uart.c
+++ b/drivers/rpmsg/rpmsg_port_uart.c
@@ -119,6 +119,10 @@ struct rpmsg_port_uart_s
   uint8_t                         rx_dbg_buf[RPMSG_PORT_UART_DBG_BUFLEN];
   int                             rx_dbg_idx;
   nxevent_t                       event;
+
+  /* Serialize the connect handshake */
+
+  mutex_t                         conn_lock;
   struct notifier_block           nb;       /* Reboot notifier block */
   pid_t                           tx_tid;
   uint8_t                         tx_staywake;
@@ -537,10 +541,21 @@ static void
 rpmsg_port_uart_process_rx_conn(FAR struct rpmsg_port_uart_s *rpuart,
                                 uint8_t ch)
 {
+  bool conned;
+
+  /* Only the EVT_CONNED update is serialized against the tx thread's
+   * check-and-send; register/unregister below may re-enter this function
+   * on the same thread through the rx worker.
+   */
+
+  nxmutex_lock(&rpuart->conn_lock);
+  conned = rpmsg_port_uart_set(rpuart, RPMSG_PORT_UART_EVT_CONNED);
+  nxmutex_unlock(&rpuart->conn_lock);
+
   if (ch == RPMSG_PORT_UART_CONNREQ)
     {
       rpmsgvbs("Connect Request Command 0x%lx\n", rpuart->event.events);
-      if (rpmsg_port_uart_set(rpuart, RPMSG_PORT_UART_EVT_CONNED))
+      if (conned)
         {
           rpmsg_port_drop_packets(&rpuart->port, RPMSG_PORT_DROP_TXQ);
           rpmsg_port_unregister(&rpuart->port);
@@ -553,7 +568,7 @@ rpmsg_port_uart_process_rx_conn(FAR struct 
rpmsg_port_uart_s *rpuart,
   else if (ch == RPMSG_PORT_UART_CONNACK)
     {
       rpmsgvbs("Connect Ack Command 0x%lx\n", rpuart->event.events);
-      if (!rpmsg_port_uart_set(rpuart, RPMSG_PORT_UART_EVT_CONNED))
+      if (!conned)
         {
           rpmsg_port_drop_packets(&rpuart->port, RPMSG_PORT_DROP_ALL);
           rpmsg_port_register(&rpuart->port, rpuart->localcpu);
@@ -913,6 +928,12 @@ static int rpmsg_port_uart_tx_thread(int argc, FAR char 
*argv[])
   rpuart->tx_tid = nxsched_gettid();
 
   rpmsg_port_uart_staywake(rpuart);
+
+  /* A CONNREQ sent after the rx thread has already answered CONNACK
+   * makes the peer register twice.
+   */
+
+  nxmutex_lock(&rpuart->conn_lock);
   if (!rpmsg_port_uart_check(rpuart, RPMSG_PORT_UART_EVT_CONNED))
     {
       rpmsgvbs("Not Connected, Send Conn Req\n");
@@ -923,6 +944,8 @@ static int rpmsg_port_uart_tx_thread(int argc, FAR char 
*argv[])
       rpmsgvbs("Connected, no need Send Conn Req\n");
     }
 
+  nxmutex_unlock(&rpuart->conn_lock);
+
   for (; ; )
     {
       while ((hdr = rpmsg_port_queue_get_buffer(txq, false)) != NULL)
@@ -1010,6 +1033,7 @@ int rpmsg_port_uart_initialize(FAR const struct 
rpmsg_port_config_s *cfg,
   rpuart->rx_state = RPMSG_PORT_UART_RX_WAIT_START;
   rpuart->tx_staywake = RPMSG_PORT_UART_STAYWAKE1;
   nxevent_init(&rpuart->event, 0);
+  nxmutex_init(&rpuart->conn_lock);
 
   /* Hardware initialize */
 
@@ -1099,6 +1123,7 @@ err_lzf:
 err_rpmsg_port:
   file_close(&rpuart->file);
 err_file:
+  nxmutex_destroy(&rpuart->conn_lock);
   nxevent_destroy(&rpuart->event);
   kmm_free(rpuart);
   return ret;

Reply via email to