Skip to content

Commit c7f2e74

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 pinheiro paschoaletto <axelpinheiro@gmail.com>
1 parent 808ee17 commit c7f2e74

File tree

2 files changed

+128
-1
lines changed

2 files changed

+128
-1
lines changed

include/zephyr/kernel.h

Lines changed: 25 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,30 @@ 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 beginning 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 The message content is copied from @a data into @a msgq and the @a data
4817+
* pointer is not retained, so the message content will not be modified
4818+
* by this function.
4819+
*
4820+
* @funcprops \isr_ok
4821+
*
4822+
* @param msgq Address of the message queue.
4823+
* @param data Pointer to the message.
4824+
* @param timeout Waiting period to add the message, or one of the special
4825+
* values K_NO_WAIT and K_FOREVER.
4826+
*
4827+
* @retval 0 Message sent.
4828+
* @retval -ENOMSG Returned without waiting or queue purged.
4829+
* @retval -EAGAIN Waiting period timed out.
4830+
*/
4831+
__syscall int k_msgq_put_urgent(struct k_msgq *msgq, const void *data, k_timeout_t timeout);
4832+
48094833
/**
48104834
* @brief Receive a message from a message queue.
48114835
*

kernel/msg_q.c

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,100 @@ int z_impl_k_msgq_put(struct k_msgq *msgq, const void *data, k_timeout_t timeout
187187
return result;
188188
}
189189

190+
int z_impl_k_msgq_put_urgent(struct k_msgq *msgq, const void *data, k_timeout_t timeout)
191+
{
192+
__ASSERT(!arch_is_in_isr() || K_TIMEOUT_EQ(timeout, K_NO_WAIT), "");
193+
194+
struct k_thread *pending_thread;
195+
k_spinlock_key_t key;
196+
int result;
197+
bool resched = false;
198+
199+
key = k_spin_lock(&msgq->lock);
200+
201+
SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_msgq, put, msgq, timeout);
202+
203+
if (msgq->used_msgs < msgq->max_msgs) {
204+
/* message queue isn't full */
205+
pending_thread = z_unpend_first_thread(&msgq->wait_q);
206+
if (unlikely(pending_thread != NULL)) {
207+
resched = true;
208+
209+
/* give message to waiting thread */
210+
(void)memcpy(pending_thread->base.swap_data, data, msgq->msg_size);
211+
/* wake up waiting thread */
212+
arch_thread_return_value_set(pending_thread, 0);
213+
z_ready_thread(pending_thread);
214+
} else {
215+
/*
216+
* urgent put = write message to the head of the queue.
217+
* this is achieved in practice by simply:
218+
*
219+
* 1. decrementing the read pointer. This effectively
220+
* opens space for the incoming message in the head of
221+
* the queue.
222+
*
223+
* 2. temporarily matching the read pointer with the
224+
* write pointer. This way the message will be written
225+
* in the recently opened space.
226+
*
227+
* 3. reverting the write pointer after the write to its
228+
* original value. The read pointer, by its turn, should
229+
* be always at the head, so it doesn't need reverting
230+
* because we just wrote to the head.
231+
*/
232+
char *original_write_ptr = msgq->write_ptr;
233+
234+
/* decrement the read pointer */
235+
msgq->read_ptr -= msgq->msg_size;
236+
if (msgq->read_ptr < msgq->buffer_start) {
237+
msgq->read_ptr = msgq->buffer_end - msgq->msg_size;
238+
}
239+
240+
/* match read and write pointers */
241+
msgq->write_ptr = msgq->read_ptr;
242+
243+
/* put message in queue */
244+
__ASSERT_NO_MSG(msgq->write_ptr >= msgq->buffer_start &&
245+
msgq->write_ptr < msgq->buffer_end);
246+
(void)memcpy(msgq->write_ptr, (char *)data, msgq->msg_size);
247+
msgq->write_ptr += msgq->msg_size;
248+
if (msgq->write_ptr == msgq->buffer_end) {
249+
msgq->write_ptr = msgq->buffer_start;
250+
}
251+
msgq->used_msgs++;
252+
253+
/* revert write pointer to the original value */
254+
msgq->write_ptr = original_write_ptr;
255+
256+
resched = handle_poll_events(msgq);
257+
}
258+
result = 0;
259+
} else if (K_TIMEOUT_EQ(timeout, K_NO_WAIT)) {
260+
/* don't wait for message space to become available */
261+
result = -ENOMSG;
262+
} else {
263+
SYS_PORT_TRACING_OBJ_FUNC_BLOCKING(k_msgq, put, msgq, timeout);
264+
265+
/* wait for put message success, failure, or timeout */
266+
_current->base.swap_data = (void *) data;
267+
268+
result = z_pend_curr(&msgq->lock, key, &msgq->wait_q, timeout);
269+
SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_msgq, put, msgq, timeout, result);
270+
return result;
271+
}
272+
273+
SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_msgq, put, msgq, timeout, result);
274+
275+
if (resched) {
276+
z_reschedule(&msgq->lock, key);
277+
} else {
278+
k_spin_unlock(&msgq->lock, key);
279+
}
280+
281+
return result;
282+
}
283+
190284
#ifdef CONFIG_USERSPACE
191285
static inline int z_vrfy_k_msgq_put(struct k_msgq *msgq, const void *data,
192286
k_timeout_t timeout)
@@ -196,6 +290,15 @@ static inline int z_vrfy_k_msgq_put(struct k_msgq *msgq, const void *data,
196290

197291
return z_impl_k_msgq_put(msgq, data, timeout);
198292
}
293+
294+
static inline int z_vrfy_k_msgq_put_urgent(struct k_msgq *msgq, const void *data,
295+
k_timeout_t timeout)
296+
{
297+
K_OOPS(K_SYSCALL_OBJ(msgq, K_OBJ_MSGQ));
298+
K_OOPS(K_SYSCALL_MEMORY_READ(data, msgq->msg_size));
299+
300+
return z_impl_k_msgq_put_urgent(msgq, data, timeout);
301+
}
199302
#include <zephyr/syscalls/k_msgq_put_mrsh.c>
200303
#endif /* CONFIG_USERSPACE */
201304

0 commit comments

Comments
 (0)