Skip to content

kernel: msgq: adding support for k_msgq_put_front and sample code #92865

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

alexpaschoaletto
Copy link
Contributor

@alexpaschoaletto alexpaschoaletto commented Jul 8, 2025

Following the examples of FreeRTOS and RTEMS, this PR introduces a k_msgq_put_front API for sending messages to the head of the queue, in a LIFO scheme. It also adds a simple sample code that demonstrates how it works.

Due to the fact that both versions of k_msgq_put share most of the code, this contribution creates an internal put_msg_in_queue function which inserts the message at the front or back of the queue depending on the flag put_at_back passed to it. Now the implementation looks like this:

/* internal function */
int put_msg_in_queue(struct k_msgq *msgq, const void *data, k_timeout_t timeout, bool put_at_back)
{
        /*
            puts message to front or back of the queue
            depending on the value or put_at_back
        */
}

int z_impl_k_msgq_put(struct k_msgq *msgq, const void *data, k_timeout_t timeout)
{
	return put_msg_in_queue(msgq, data, timeout, true);
}

int z_impl_k_msgq_put_front(struct k_msgq *msgq, const void *data, k_timeout_t timeout)
{
	return put_msg_in_queue(msgq, data, timeout, false);
}

note: some work concerning mainly docs and ci/cd still needs updating, but the bulk of the contribution is here. I'd like to have some opinions on this contribution before taking the time to do everyhing properly.

Closes #46339

@alexpaschoaletto alexpaschoaletto changed the title kernel: msgq: adding support for k_msgq_put_urgent and sample code kernel: msgq: adding support for k_msgq_put_urgent and sample code Jul 8, 2025
@alexpaschoaletto alexpaschoaletto force-pushed the message-queue-improvements branch from d4fac33 to 85938e2 Compare July 8, 2025 22:06
@kartben kartben assigned andyross and peter-mitsis and unassigned kartben Jul 9, 2025
Copy link
Contributor

@andyross andyross left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A design nitpick around the cut/paste feel of the change.

Also: please isolate changes to the sample to a separate commit from the semantic change in the kernel.

And while a sample can be used as a test case, it's really best to put an actual test case of this functionality into tests/kernel/msgq/msgq_api

kernel/msg_q.c Outdated

/* give message to waiting thread */
(void)memcpy(pending_thread->base.swap_data, data,
msgq->msg_size);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not loving the duplication of the implementation code. Ideally all this should be shared. In particular maintenance-quality-issues are at their most important in code surrounding memory copies into/out-of caller pointers (which can cross security boundaries if CONFIG_USERSPACE=y!). Might take some refactoring to make that happen, obviously.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand and agree, but at first I really didn't want to touch in the already existing k_msgq_put function. So should I do something like this, then?

int _copy_to_queue ( ... , bool should_copy_to_back) {
  // shared implementation goes here
}

int z_impl_k_msgq_put( ... ) {
  return _copy_to_queue( ... , true);
}

int z_impl_k_msgq_put_urgent( ... ) {
  return _copy_to_queue( ..., , false);
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW I have done just that to avoid code duplication.

}

received[BUF_SIZE - 1] = '\0';
/* we expect to see CBA012345... */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While this is a good note for understanding, it would be even better for this to be a test that actually checked messages were received in the expected order.

Copy link
Contributor Author

@alexpaschoaletto alexpaschoaletto Jul 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. For now I have refactored the sample code to have a regex to check the sample output (with the message sequence) on the tests. I intend to do the proper ZTEST thing as you suggested as well, but I'd like to settle on the implementation before that.

Copy link
Member

@TaiJuWu TaiJuWu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add reference: #46339 to PR description.
Also this feature is good to be optional and it need more test.

kernel/msg_q.c Outdated
/* 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);
Copy link
Member

@TaiJuWu TaiJuWu Jul 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add an additional trace log to facilitate easier debugging.

Copy link
Contributor Author

@alexpaschoaletto alexpaschoaletto Jul 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this idea, however I'm not certain on how to refactor this part. would this be just changing put by put_urgent (or whatever naming convention we end up deciding)? Like this:

SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_msgq, put_urgent, msgq, timeout, 0);

Copy link
Member

@TaiJuWu TaiJuWu Jul 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can refer #71195
I think I finished most implements at that time.

@alexpaschoaletto alexpaschoaletto force-pushed the message-queue-improvements branch 4 times, most recently from 34fffd8 to 66d7bfd Compare July 9, 2025 21:34
@alexpaschoaletto
Copy link
Contributor Author

Please add reference: #46339 to PR description. Also this feature is good to be optional and it need more test.

done! not sure what you mean by "good to be optional", though. Proper tests will be done soon - I wanted some feedback on this contribution before taking the effort (if for some reason this was immediately discarded by reviewers, then it would be a waste of energy).

@alexpaschoaletto alexpaschoaletto force-pushed the message-queue-improvements branch from 66d7bfd to 347fdde Compare July 9, 2025 22:27
@TaiJuWu
Copy link
Member

TaiJuWu commented Jul 10, 2025

Please add reference: #46339 to PR description. Also this feature is good to be optional and it need more test.

done! not sure what you mean by "good to be optional", though. Proper tests will be done soon - I wanted some feedback on this contribution before taking the effort (if for some reason this was immediately discarded by reviewers, then it would be a waste of energy).

In my mind, the feature is not required for every developer so we can be optional and make the user to decide enabling it or not, this can reduce code size.

@alexpaschoaletto alexpaschoaletto force-pushed the message-queue-improvements branch 2 times, most recently from 3ca45a2 to 6ccbe34 Compare July 10, 2025 22:36
@github-actions github-actions bot added the area: Tracing Tracing label Jul 15, 2025
@github-actions github-actions bot requested a review from teburd July 15, 2025 18:59
@alexpaschoaletto alexpaschoaletto force-pushed the message-queue-improvements branch from 1dc7e6e to 3b88b4a Compare July 15, 2025 19:02

[producer] sending: 0
[producer] sending: 1
[producer] sending: A (urgent)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

urgent or front?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in the context of the sample, the publisher thread sends normal and urgent messages. It's not related to the API naming.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it, thanks.

@peter-mitsis
Copy link
Contributor

Once the minor compliance check is fixed, I expect I will be giving this a +1.

@alexpaschoaletto alexpaschoaletto force-pushed the message-queue-improvements branch 2 times, most recently from 68bfba2 to 8223338 Compare July 16, 2025 18:24
andyross
andyross previously approved these changes Jul 16, 2025
peter-mitsis
peter-mitsis previously approved these changes Jul 16, 2025
Copy link
Contributor

@JarmouniA JarmouniA left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly nits

@TaiJuWu
Copy link
Member

TaiJuWu commented Jul 17, 2025

it is a test failure, is it excepted?

The reason is described in #92865 (comment)

/**
 * @brief Put a message to a full queue for behavior test
 *
 * @details
 * - Thread A put message to a full message queue and then sleep
 * Thread B put a new message to the queue then pending on it.
 * - Thread A get all messages from message queue and check the behavior.
 *
 * @see k_msgq_put(), k_msgq_put_front()
 */
ZTEST(msgq_api_1cpu, test_msgq_pending)
{
	uint32_t rx_data;
	int pri = k_thread_priority_get(k_current_get()) - 1;
	int ret;

	k_msgq_init(&msgq1, tbuffer, MSG_SIZE, 2);
	ret = k_sem_init(&end_sema, 0, 1);
	zassert_equal(ret, 0);

	ret = IS_ENABLED(CONFIG_TEST_MSGQ_PREPEND) ?
		k_msgq_put_front(&msgq1, &data[1], K_NO_WAIT) :
		k_msgq_put(&msgq1, &data[0], K_NO_WAIT);
	zassert_equal(ret, 0);
	ret = IS_ENABLED(CONFIG_TEST_MSGQ_PREPEND) ?
		k_msgq_put(&msgq1, &data[0], K_NO_WAIT) :
		k_msgq_put_front(&msgq1, &data[1], K_NO_WAIT);
	zassert_equal(ret, 0);

	k_tid_t tid = k_thread_create(&tdata2, tstack2, STACK_SIZE,
					prepend_full_entry, &msgq1, NULL,
					NULL, pri, 0, K_NO_WAIT);

	/* that putting thread is being blocked now */
	k_sem_take(&end_sema, K_FOREVER);
	zassert_equal(tid->base.thread_state, _THREAD_PENDING);
	ret = k_msgq_get(&msgq1, &rx_data, K_FOREVER);
	zassert_equal(ret, 0);
	zassert_equal(rx_data, data[1]);

	ret = k_msgq_get(&msgq1, &rx_data, K_FOREVER);
	zassert_equal(ret, 0);
	zassert_equal(rx_data, msg3);

	ret = k_msgq_get(&msgq1, &rx_data, K_FOREVER);
	zassert_equal(ret, 0);
	zassert_equal(rx_data, data[0]);
	k_thread_abort(tid);
}

@JarmouniA JarmouniA added the DNM This PR should not be merged (Do Not Merge) label Jul 19, 2025
@alexpaschoaletto alexpaschoaletto dismissed stale reviews from peter-mitsis and andyross via 985db90 July 23, 2025 14:31
@alexpaschoaletto alexpaschoaletto force-pushed the message-queue-improvements branch from 8223338 to 985db90 Compare July 23, 2025 14:31
This commit introduces the k_msgq_put_front API for sending
messages to a queue in a LIFO scheme.

Signed-off-by: Alexander Paschoaletto <[email protected]>
this commit adds a sample code to illustrate the base usage
of message queues. a producer and a consumer thread work
together, exchanging messages in a FIFO (for normal payloads)
and LIFO (for higher priority payloads) schemes.

Signed-off-by: Alexander Paschoaletto <[email protected]>
This commit adds the tracing macros and functions related
specifically to the k_msgq_put_front API.

Signed-off-by: Alexander Paschoaletto <[email protected]>
@alexpaschoaletto alexpaschoaletto force-pushed the message-queue-improvements branch from 985db90 to 3a60725 Compare July 23, 2025 14:42
@JarmouniA JarmouniA removed the DNM This PR should not be merged (Do Not Merge) label Jul 23, 2025
Copy link

@alexpaschoaletto
Copy link
Contributor Author

it is a test failure, is it excepted?

The reason is described in #92865 (comment)

I don't know if I understood. What exactly is to fail here?

Copy link
Contributor

@andyross andyross left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refresh +1

@TaiJuWu
Copy link
Member

TaiJuWu commented Jul 25, 2025

it is a test failure, is it excepted?
The reason is described in #92865 (comment)

I don't know if I understood. What exactly is to fail here?

This test covers the behavior of putting a message into the message queue when it is full.
In theory, it should pass, but in reality, this test fails.
The reason is that when the buffer is full, Thread A gets pended (blocked).
If Thread B later calls the get function, it will wake up Thread A, allowing it to resume and put the message into the queue.
In this situation, we need to know whether Thread A should continue with put to front or put to end.

Does this scenario make sense?

@cfriedt cfriedt merged commit 8c03410 into zephyrproject-rtos:main Jul 25, 2025
30 of 31 checks passed
Copy link

Hi @alexpaschoaletto!
Congratulations on getting your very first Zephyr pull request merged 🎉🥳. This is a fantastic achievement, and we're thrilled to have you as part of our community!

To celebrate this milestone and showcase your contribution, we'd love to award you the Zephyr Technical Contributor badge. If you're interested, please claim your badge by filling out this form: Claim Your Zephyr Badge.

Thank you for your valuable input, and we look forward to seeing more of your contributions in the future! 🪁

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Zephyr message queue: add LIFO operation
8 participants