Skip to content

Commit dc9cbca

Browse files
alexpaschoalettoAlexander pinheiro paschoaletto
authored andcommitted
kernel: msgq: adding support to k_msgq_put_urgent
This commit introduces the k_msgq_put_urgent API for sending messages to a queue in a LIFO scheme. Signed-off-by: Alexander Paschoaletto <axelpinheiro@gmail.com>
1 parent 808ee17 commit dc9cbca

File tree

2 files changed

+91
-10
lines changed

2 files changed

+91
-10
lines changed

include/zephyr/kernel.h

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4785,7 +4785,7 @@ __syscall int k_msgq_alloc_init(struct k_msgq *msgq, size_t msg_size,
47854785
int k_msgq_cleanup(struct k_msgq *msgq);
47864786

47874787
/**
4788-
* @brief Send a message to a message queue.
4788+
* @brief Send a message to the end of a message queue.
47894789
*
47904790
* This routine sends a message to message queue @a q.
47914791
*
@@ -4806,6 +4806,33 @@ int k_msgq_cleanup(struct k_msgq *msgq);
48064806
*/
48074807
__syscall int k_msgq_put(struct k_msgq *msgq, const void *data, k_timeout_t timeout);
48084808

4809+
/**
4810+
* @brief Send a message to the front of a message queue.
4811+
*
4812+
* This routine sends a message to the beginning (head) of message queue @a q.
4813+
* Messages sent with this method will be retrieved before any pre-existing
4814+
* messages in the queue.
4815+
*
4816+
* @note if there is no space in the message queue, this function will
4817+
* behave the same as k_msgq_put.
4818+
*
4819+
* @note The message content is copied from @a data into @a msgq and the @a data
4820+
* pointer is not retained, so the message content will not be modified
4821+
* by this function.
4822+
*
4823+
* @funcprops \isr_ok
4824+
*
4825+
* @param msgq Address of the message queue.
4826+
* @param data Pointer to the message.
4827+
* @param timeout Waiting period to add the message, or one of the special
4828+
* values K_NO_WAIT and K_FOREVER.
4829+
*
4830+
* @retval 0 Message sent.
4831+
* @retval -ENOMSG Returned without waiting or queue purged.
4832+
* @retval -EAGAIN Waiting period timed out.
4833+
*/
4834+
__syscall int k_msgq_put_front(struct k_msgq *msgq, const void *data, k_timeout_t timeout);
4835+
48094836
/**
48104837
* @brief Receive a message from a message queue.
48114838
*

kernel/msg_q.c

Lines changed: 63 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -124,11 +124,8 @@ int k_msgq_cleanup(struct k_msgq *msgq)
124124
return 0;
125125
}
126126

127-
128-
int z_impl_k_msgq_put(struct k_msgq *msgq, const void *data, k_timeout_t timeout)
127+
static inline int put_msg_in_queue(struct k_msgq *msgq, const void *data, k_timeout_t timeout, bool put_at_back)
129128
{
130-
__ASSERT(!arch_is_in_isr() || K_TIMEOUT_EQ(timeout, K_NO_WAIT), "");
131-
132129
struct k_thread *pending_thread;
133130
k_spinlock_key_t key;
134131
int result;
@@ -150,13 +147,50 @@ int z_impl_k_msgq_put(struct k_msgq *msgq, const void *data, k_timeout_t timeout
150147
arch_thread_return_value_set(pending_thread, 0);
151148
z_ready_thread(pending_thread);
152149
} else {
153-
/* put message in queue */
154150
__ASSERT_NO_MSG(msgq->write_ptr >= msgq->buffer_start &&
155151
msgq->write_ptr < msgq->buffer_end);
156-
(void)memcpy(msgq->write_ptr, (char *)data, msgq->msg_size);
157-
msgq->write_ptr += msgq->msg_size;
158-
if (msgq->write_ptr == msgq->buffer_end) {
159-
msgq->write_ptr = msgq->buffer_start;
152+
if (put_at_back) {
153+
/*
154+
* writing a message to the back of the queue is
155+
* simple and effective: copy the message, then
156+
* increment write_ptr.
157+
*/
158+
(void)memcpy(msgq->write_ptr, (char *)data, msgq->msg_size);
159+
msgq->write_ptr += msgq->msg_size;
160+
if (msgq->write_ptr == msgq->buffer_end) {
161+
msgq->write_ptr = msgq->buffer_start;
162+
}
163+
} else {
164+
/*
165+
* writing a message to the head of the queue is
166+
* less obvious, but it can be achieved by simply
167+
* following these steps:
168+
*
169+
* 1. decrementing the read pointer. This effectively
170+
* opens space for the incoming message in the head of
171+
* the queue.
172+
*
173+
* 2. temporarily matching the write pointer with the
174+
* read pointer. This way the message will be written
175+
* in the recently opened space.
176+
*
177+
* 3. reverting the write pointer after the write to its
178+
* original value. The read pointer, by its turn, should
179+
* be always at the head, so it doesn't need reverting
180+
* because we just wrote to the head.
181+
*
182+
* ...but this is inefficient because we need to go back
183+
* and forth with the value of write_ptr; note that it
184+
* becomes equal to read_ptr just to be restored afterwards.
185+
* A much more efficient solution is to simply write the
186+
* message directly to read_ptr's address after step 1,
187+
* which avoids needing to perform steps 2 and 3 altogether.
188+
*/
189+
if (msgq->read_ptr == msgq->buffer_start) {
190+
msgq->read_ptr = msgq->buffer_end;
191+
}
192+
msgq->read_ptr -= msgq->msg_size;
193+
(void)memcpy(msgq->read_ptr, (char *)data, msgq->msg_size);
160194
}
161195
msgq->used_msgs++;
162196
resched = handle_poll_events(msgq);
@@ -187,6 +221,17 @@ int z_impl_k_msgq_put(struct k_msgq *msgq, const void *data, k_timeout_t timeout
187221
return result;
188222
}
189223

224+
225+
int z_impl_k_msgq_put(struct k_msgq *msgq, const void *data, k_timeout_t timeout)
226+
{
227+
return put_msg_in_queue(msgq, data, timeout, true);
228+
}
229+
230+
int z_impl_k_msgq_put_front(struct k_msgq *msgq, const void *data, k_timeout_t timeout)
231+
{
232+
return put_msg_in_queue(msgq, data, timeout, false);
233+
}
234+
190235
#ifdef CONFIG_USERSPACE
191236
static inline int z_vrfy_k_msgq_put(struct k_msgq *msgq, const void *data,
192237
k_timeout_t timeout)
@@ -196,6 +241,15 @@ static inline int z_vrfy_k_msgq_put(struct k_msgq *msgq, const void *data,
196241

197242
return z_impl_k_msgq_put(msgq, data, timeout);
198243
}
244+
245+
static inline int z_vrfy_k_msgq_put_front(struct k_msgq *msgq, const void *data,
246+
k_timeout_t timeout)
247+
{
248+
K_OOPS(K_SYSCALL_OBJ(msgq, K_OBJ_MSGQ));
249+
K_OOPS(K_SYSCALL_MEMORY_READ(data, msgq->msg_size));
250+
251+
return z_impl_k_msgq_put_front(msgq, data, timeout);
252+
}
199253
#include <zephyr/syscalls/k_msgq_put_mrsh.c>
200254
#endif /* CONFIG_USERSPACE */
201255

0 commit comments

Comments
 (0)