Skip to content

Commit aa19327

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 aa19327

File tree

2 files changed

+91
-8
lines changed

2 files changed

+91
-8
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 & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,7 @@ 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
{
130129
__ASSERT(!arch_is_in_isr() || K_TIMEOUT_EQ(timeout, K_NO_WAIT), "");
131130

@@ -150,13 +149,50 @@ int z_impl_k_msgq_put(struct k_msgq *msgq, const void *data, k_timeout_t timeout
150149
arch_thread_return_value_set(pending_thread, 0);
151150
z_ready_thread(pending_thread);
152151
} else {
153-
/* put message in queue */
154152
__ASSERT_NO_MSG(msgq->write_ptr >= msgq->buffer_start &&
155153
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;
154+
if (put_at_back) {
155+
/*
156+
* writing a message to the back of the queue is
157+
* simple and effective: copy the message, then
158+
* increment write_ptr.
159+
*/
160+
(void)memcpy(msgq->write_ptr, (char *)data, msgq->msg_size);
161+
msgq->write_ptr += msgq->msg_size;
162+
if (msgq->write_ptr == msgq->buffer_end) {
163+
msgq->write_ptr = msgq->buffer_start;
164+
}
165+
} else {
166+
/*
167+
* writing a message to the head of the queue is
168+
* less obvious, but it can be achieved by simply
169+
* following these steps:
170+
*
171+
* 1. decrementing the read pointer. This effectively
172+
* opens space for the incoming message in the head of
173+
* the queue.
174+
*
175+
* 2. temporarily matching the write pointer with the
176+
* read pointer. This way the message will be written
177+
* in the recently opened space.
178+
*
179+
* 3. reverting the write pointer after the write to its
180+
* original value. The read pointer, by its turn, should
181+
* be always at the head, so it doesn't need reverting
182+
* because we just wrote to the head.
183+
*
184+
* ...but this is inefficient because we need to go back
185+
* and forth with the value of write_ptr; note that it
186+
* becomes equal to read_ptr just to be restored afterwards.
187+
* A much more efficient solution is to simply write the
188+
* message directly to read_ptr's address after step 1,
189+
* which avoids needing to perform steps 2 and 3 altogether.
190+
*/
191+
if (msgq->read_ptr == msgq->buffer_start) {
192+
msgq->read_ptr = msgq->buffer_end;
193+
}
194+
msgq->read_ptr -= msgq->msg_size;
195+
(void)memcpy(msgq->read_ptr, (char *)data, msgq->msg_size);
160196
}
161197
msgq->used_msgs++;
162198
resched = handle_poll_events(msgq);
@@ -187,6 +223,17 @@ int z_impl_k_msgq_put(struct k_msgq *msgq, const void *data, k_timeout_t timeout
187223
return result;
188224
}
189225

226+
227+
int z_impl_k_msgq_put(struct k_msgq *msgq, const void *data, k_timeout_t timeout)
228+
{
229+
return put_msg_in_queue(msgq, data, timeout, true);
230+
}
231+
232+
int z_impl_k_msgq_put_front(struct k_msgq *msgq, const void *data, k_timeout_t timeout)
233+
{
234+
return put_msg_in_queue(msgq, data, timeout, false);
235+
}
236+
190237
#ifdef CONFIG_USERSPACE
191238
static inline int z_vrfy_k_msgq_put(struct k_msgq *msgq, const void *data,
192239
k_timeout_t timeout)
@@ -196,6 +243,15 @@ static inline int z_vrfy_k_msgq_put(struct k_msgq *msgq, const void *data,
196243

197244
return z_impl_k_msgq_put(msgq, data, timeout);
198245
}
246+
247+
static inline int z_vrfy_k_msgq_put_front(struct k_msgq *msgq, const void *data,
248+
k_timeout_t timeout)
249+
{
250+
K_OOPS(K_SYSCALL_OBJ(msgq, K_OBJ_MSGQ));
251+
K_OOPS(K_SYSCALL_MEMORY_READ(data, msgq->msg_size));
252+
253+
return z_impl_k_msgq_put_front(msgq, data, timeout);
254+
}
199255
#include <zephyr/syscalls/k_msgq_put_mrsh.c>
200256
#endif /* CONFIG_USERSPACE */
201257

0 commit comments

Comments
 (0)