Skip to content

Commit ba43359

Browse files
committed
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 <kai.vehmanen@linux.intel.com>
1 parent 172589b commit ba43359

1 file changed

Lines changed: 13 additions & 3 deletions

File tree

src/ipc/ipc-common.c

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -254,9 +254,9 @@ void ipc_msg_send(struct ipc_msg *msg, void *data, bool high_priority)
254254
list_item_append(&msg->list, &ipc->msg_list);
255255
}
256256

257-
schedule_ipc_worker();
258-
259257
k_spin_unlock(&ipc->lock, key);
258+
259+
schedule_ipc_worker();
260260
}
261261
EXPORT_SYMBOL(ipc_msg_send);
262262

@@ -265,15 +265,25 @@ static void ipc_work_handler(struct k_work *work)
265265
{
266266
struct ipc *ipc = ipc_get();
267267
k_spinlock_key_t key;
268+
bool more_to_send = false;
268269

269270
ipc_send_queued_msg();
270271

271272
key = k_spin_lock(&ipc->lock);
272273

273274
if (!list_is_empty(&ipc->msg_list) && !ipc->pm_prepare_D3)
274-
schedule_ipc_worker();
275+
more_to_send = true;
275276

276277
k_spin_unlock(&ipc->lock, key);
278+
279+
/*
280+
* If there's a race and the message is already sent and/or
281+
* prepare_D3 is set, we may do an extra wake-up of the
282+
* worker, but it is harmless as the worker will take
283+
* the lock and check the status again.
284+
*/
285+
if (more_to_send)
286+
schedule_ipc_worker();
277287
}
278288
#endif
279289

0 commit comments

Comments
 (0)