From 9a848b3ad4af76769192c08b5a51643be1882be6 Mon Sep 17 00:00:00 2001 From: Lucas Dietrich Date: Tue, 3 May 2022 21:01:30 +0000 Subject: [PATCH] kernel: workq: Add internal function z_work_submit_to_queue() This adds the internal function z_work_submit_to_queue(), which submits the work item to the queue but doesn't force the thread to yield, compared to the public function k_work_submit_to_queue(). When called from poll.c in the context of k_work_poll events, it ensures that the thread does not yield in the context of the spinlock of object that became available. Fixes #45267 Signed-off-by: Lucas Dietrich --- kernel/poll.c | 5 ++++- kernel/work.c | 27 +++++++++++++++++++++++---- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/kernel/poll.c b/kernel/poll.c index fb700bf7c8de..3feaed80f6ef 100644 --- a/kernel/poll.c +++ b/kernel/poll.c @@ -576,6 +576,9 @@ static void triggered_work_expiration_handler(struct _timeout *timeout) k_work_submit_to_queue(twork->workq, &twork->work); } +extern int z_work_submit_to_queue(struct k_work_q *queue, + struct k_work *work); + static int signal_triggered_work(struct k_poll_event *event, uint32_t status) { struct z_poller *poller = event->poller; @@ -587,7 +590,7 @@ static int signal_triggered_work(struct k_poll_event *event, uint32_t status) z_abort_timeout(&twork->timeout); twork->poll_result = 0; - k_work_submit_to_queue(work_q, &twork->work); + z_work_submit_to_queue(work_q, &twork->work); } return 0; diff --git a/kernel/work.c b/kernel/work.c index 11e849ffd728..6ef001f24b49 100644 --- a/kernel/work.c +++ b/kernel/work.c @@ -355,19 +355,38 @@ static int submit_to_queue_locked(struct k_work *work, return ret; } -int k_work_submit_to_queue(struct k_work_q *queue, - struct k_work *work) +/* Submit work to a queue but do not yield the current thread. + * + * Intended for internal use. + * + * See also submit_to_queue_locked(). + * + * @param queuep pointer to a queue reference. + * @param work the work structure to be submitted + * + * @retval see submit_to_queue_locked() + */ +int z_work_submit_to_queue(struct k_work_q *queue, + struct k_work *work) { __ASSERT_NO_MSG(work != NULL); k_spinlock_key_t key = k_spin_lock(&lock); - SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_work, submit_to_queue, queue, work); - int ret = submit_to_queue_locked(work, &queue); k_spin_unlock(&lock, key); + return ret; +} + +int k_work_submit_to_queue(struct k_work_q *queue, + struct k_work *work) +{ + SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_work, submit_to_queue, queue, work); + + int ret = z_work_submit_to_queue(queue, work); + /* submit_to_queue_locked() won't reschedule on its own * (really it should, otherwise this process will result in * spurious calls to z_swap() due to the race), so do it here