From 48939cb44b615516e04f57d7706f37ce0afc6b99 Mon Sep 17 00:00:00 2001 From: Peter Mitsis Date: Mon, 16 Dec 2024 17:12:30 -0800 Subject: [PATCH] kernel: msgq: Allow for fast returns 1. Fixes a performance issue in k_msgq_put() to allow for a fast return path when handling a poll event does nothing. 2. Allows for a fast return path in k_msgq_purge() when no threads were awakened. Signed-off-by: Peter Mitsis --- kernel/msg_q.c | 42 ++++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/kernel/msg_q.c b/kernel/msg_q.c index 96306d0d67d..7b8686ffa63 100644 --- a/kernel/msg_q.c +++ b/kernel/msg_q.c @@ -132,6 +132,7 @@ int z_impl_k_msgq_put(struct k_msgq *msgq, const void *data, k_timeout_t timeout struct k_thread *pending_thread; k_spinlock_key_t key; int result; + bool resched = false; key = k_spin_lock(&msgq->lock); @@ -141,16 +142,13 @@ int z_impl_k_msgq_put(struct k_msgq *msgq, const void *data, k_timeout_t timeout /* message queue isn't full */ pending_thread = z_unpend_first_thread(&msgq->wait_q); if (unlikely(pending_thread != NULL)) { - SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_msgq, put, msgq, timeout, 0); + resched = true; /* give message to waiting thread */ - (void)memcpy(pending_thread->base.swap_data, data, - msgq->msg_size); + (void)memcpy(pending_thread->base.swap_data, data, msgq->msg_size); /* wake up waiting thread */ arch_thread_return_value_set(pending_thread, 0); z_ready_thread(pending_thread); - z_reschedule(&msgq->lock, key); - return 0; } else { /* put message in queue */ __ASSERT_NO_MSG(msgq->write_ptr >= msgq->buffer_start && @@ -161,7 +159,7 @@ int z_impl_k_msgq_put(struct k_msgq *msgq, const void *data, k_timeout_t timeout msgq->write_ptr = msgq->buffer_start; } msgq->used_msgs++; - (void)handle_poll_events(msgq); + resched = handle_poll_events(msgq); } result = 0; } else if (K_TIMEOUT_EQ(timeout, K_NO_WAIT)) { @@ -180,7 +178,11 @@ int z_impl_k_msgq_put(struct k_msgq *msgq, const void *data, k_timeout_t timeout SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_msgq, put, msgq, timeout, result); - z_reschedule(&msgq->lock, key); + if (resched) { + z_reschedule(&msgq->lock, key); + } else { + k_spin_unlock(&msgq->lock, key); + } return result; } @@ -222,6 +224,7 @@ int z_impl_k_msgq_get(struct k_msgq *msgq, void *data, k_timeout_t timeout) k_spinlock_key_t key; struct k_thread *pending_thread; int result; + bool resched = false; key = k_spin_lock(&msgq->lock); @@ -255,11 +258,7 @@ int z_impl_k_msgq_get(struct k_msgq *msgq, void *data, k_timeout_t timeout) /* wake up waiting thread */ arch_thread_return_value_set(pending_thread, 0); z_ready_thread(pending_thread); - z_reschedule(&msgq->lock, key); - - SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_msgq, get, msgq, timeout, 0); - - return 0; + resched = true; } result = 0; } else if (K_TIMEOUT_EQ(timeout, K_NO_WAIT)) { @@ -278,7 +277,11 @@ int z_impl_k_msgq_get(struct k_msgq *msgq, void *data, k_timeout_t timeout) SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_msgq, get, msgq, timeout, result); - k_spin_unlock(&msgq->lock, key); + if (resched) { + z_reschedule(&msgq->lock, key); + } else { + k_spin_unlock(&msgq->lock, key); + } return result; } @@ -379,22 +382,29 @@ void z_impl_k_msgq_purge(struct k_msgq *msgq) { k_spinlock_key_t key; struct k_thread *pending_thread; + bool resched = false; key = k_spin_lock(&msgq->lock); SYS_PORT_TRACING_OBJ_FUNC(k_msgq, purge, msgq); /* wake up any threads that are waiting to write */ - for (pending_thread = z_unpend_first_thread(&msgq->wait_q); pending_thread != NULL; - pending_thread = z_unpend_first_thread(&msgq->wait_q)) { + for (pending_thread = z_unpend_first_thread(&msgq->wait_q); + pending_thread != NULL; + pending_thread = z_unpend_first_thread(&msgq->wait_q)) { arch_thread_return_value_set(pending_thread, -ENOMSG); z_ready_thread(pending_thread); + resched = true; } msgq->used_msgs = 0; msgq->read_ptr = msgq->write_ptr; - z_reschedule(&msgq->lock, key); + if (resched) { + z_reschedule(&msgq->lock, key); + } else { + k_spin_unlock(&msgq->lock, key); + } } #ifdef CONFIG_USERSPACE