This is an automated email from the ASF dual-hosted git repository. casaroli pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 8c0d6b9957d3835f895066c000a1778f7a653bf5 Author: zhangkai25 <[email protected]> AuthorDate: Wed Apr 1 10:45:56 2026 +0800 net/can: Fix send buffer notify race. can_sendbuffer_notify() uses nxsem_get_value() to check if any thread is waiting on the send semaphore before posting. However, there is a race window between releasing the locks in conn_dev_sem_timedwait() and nxsem_wait(). If a higher-priority workqueue thread (e.g., TX completion handler) runs in this window and calls can_sendbuffer_notify(), it sees val == 0 (no waiter yet) and skips the post. The send thread then enters sem_wait but never gets woken up, causing permanent blocking. Change val < 0 to val < 1 so that the notify also posts when val is 0. This ensures the semaphore value becomes 1 before the send thread calls sem_wait, allowing it to return immediately. val cannot accumulate beyond 1 since val > 0 is not posted. Because the semaphore can now be posted while nobody waits, can_sendmsg() checks the send buffer limit again after every wake-up instead of only once, so a send never queues past the limit. A frame is always accepted into an empty queue, so a send buffer smaller than one frame cannot block the socket forever. This is the CAN part of the original change, which also fixed UDP, TCP and packet sockets. Assisted-by: Claude:claude-opus-5-5 Signed-off-by: zhangkai25 <[email protected]> Signed-off-by: p-szafonimateusz <[email protected]> --- net/can/can_sendmsg_buffered.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/net/can/can_sendmsg_buffered.c b/net/can/can_sendmsg_buffered.c index 40773022a4d..9b2a6138d4d 100644 --- a/net/can/can_sendmsg_buffered.c +++ b/net/can/can_sendmsg_buffered.c @@ -244,8 +244,14 @@ ssize_t can_sendmsg(FAR struct socket *psock, FAR const struct msghdr *msg, conn_dev_lock(&conn->sconn, dev); #if CONFIG_NET_SEND_BUFSIZE > 0 - if ((iob_get_queue_size(&conn->write_q) + msg->msg_iov->iov_len) > - conn->sndbufs) + /* Wait until the frame fits. The semaphore can be posted while there is + * still no room, so check again after every wake-up. A frame is always + * accepted into an empty queue, even if it is larger than sndbufs. + */ + + while (!IOB_QEMPTY(&conn->write_q) && + (iob_get_queue_size(&conn->write_q) + msg->msg_iov->iov_len) > + conn->sndbufs) { /* send buffer size exceeds the send limit */ @@ -475,7 +481,7 @@ void can_sendbuffer_notify(FAR struct can_conn_s *conn) int val = 0; nxsem_get_value(&conn->sndsem, &val); - if (val < 0) + if (val < 1) { nxsem_post(&conn->sndsem); }
