From ba4335992b8e1b0585245d6a65167a9e75d8d025 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Fri, 15 Aug 2025 15:52:13 +0300 Subject: [PATCH] ipc: do not hold a spinlock when calling schedule_ipc_worker() Calling schedule_ipc_worker() with spinlock held is not stricly required. schedule_ipc_worker() calls k_work_schedule_for_queue() and the Zephyr workqueue has an internal lock protecting the workqueue structures. Keeping spinlock held during the call does lead to complex scenarios to debug and verify as schedule_ipc_worker() itself is dispatched from a work queue. Simplify the flow and release spinlock before rescheduling the worker. In ipc_work_handler(), this leaves a small window where the message is just sent after we release the spinlock, and before we call schedule_ipc_worker(). This is however harmless, as in worst case the IPC worker is woken up one extra time. Signed-off-by: Kai Vehmanen --- src/ipc/ipc-common.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/ipc/ipc-common.c b/src/ipc/ipc-common.c index 2368ea9163fd..ea97c5cea1ae 100644 --- a/src/ipc/ipc-common.c +++ b/src/ipc/ipc-common.c @@ -254,9 +254,9 @@ void ipc_msg_send(struct ipc_msg *msg, void *data, bool high_priority) list_item_append(&msg->list, &ipc->msg_list); } - schedule_ipc_worker(); - k_spin_unlock(&ipc->lock, key); + + schedule_ipc_worker(); } EXPORT_SYMBOL(ipc_msg_send); @@ -265,15 +265,25 @@ static void ipc_work_handler(struct k_work *work) { struct ipc *ipc = ipc_get(); k_spinlock_key_t key; + bool more_to_send = false; ipc_send_queued_msg(); key = k_spin_lock(&ipc->lock); if (!list_is_empty(&ipc->msg_list) && !ipc->pm_prepare_D3) - schedule_ipc_worker(); + more_to_send = true; k_spin_unlock(&ipc->lock, key); + + /* + * If there's a race and the message is already sent and/or + * prepare_D3 is set, we may do an extra wake-up of the + * worker, but it is harmless as the worker will take + * the lock and check the status again. + */ + if (more_to_send) + schedule_ipc_worker(); } #endif