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;