Skip to content

Commit 4c0468b

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 4c0468b

File tree

2 files changed

+92
-8
lines changed

2 files changed

+92
-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: 64 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -124,8 +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,
128+
k_timeout_t timeout, bool put_at_back)
129129
{
130130
__ASSERT(!arch_is_in_isr() || K_TIMEOUT_EQ(timeout, K_NO_WAIT), "");
131131

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

227+
228+
int z_impl_k_msgq_put(struct k_msgq *msgq, const void *data, k_timeout_t timeout)
229+
{
230+
return put_msg_in_queue(msgq, data, timeout, true);
231+
}
232+
233+
int z_impl_k_msgq_put_front(struct k_msgq *msgq, const void *data, k_timeout_t timeout)
234+
{
235+
return put_msg_in_queue(msgq, data, timeout, false);
236+
}
237+
190238
#ifdef CONFIG_USERSPACE
191239
static inline int z_vrfy_k_msgq_put(struct k_msgq *msgq, const void *data,
192240
k_timeout_t timeout)
@@ -196,6 +244,15 @@ static inline int z_vrfy_k_msgq_put(struct k_msgq *msgq, const void *data,
196244

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

0 commit comments

Comments
 (0)