diff --git a/core/include/msg.h b/core/include/msg.h index 96ab47ea2e..90119bcdb5 100644 --- a/core/include/msg.h +++ b/core/include/msg.h @@ -411,8 +411,17 @@ unsigned msg_queue_capacity(kernel_pid_t pid); */ void msg_init_queue(msg_t *array, int num); +/** + * @brief Number of messages to be maximally printed through @ref msg_queue_print + */ +#ifndef CONFIG_MSG_QUEUE_PRINT_MAX +# define CONFIG_MSG_QUEUE_PRINT_MAX 16U +#endif + /** * @brief Prints the message queue of the current thread. + * + * @note Prints at most CONFIG_MSG_QUEUE_PRINT_MAX messages. */ void msg_queue_print(void); diff --git a/core/msg.c b/core/msg.c index 13d2b4eece..9e46fff91d 100644 --- a/core/msg.c +++ b/core/msg.c @@ -21,8 +21,10 @@ */ #include +#include #include #include +#include "macros/utils.h" #include "sched.h" #include "msg.h" #include "msg_bus.h" @@ -495,26 +497,50 @@ void msg_queue_print(void) unsigned state = irq_disable(); thread_t *thread = thread_get_active(); - unsigned msg_counter = msg_avail(); + unsigned msg_count = msg_avail(); - if (msg_counter < 1) { + if (msg_count < 1) { /* no msg queue */ irq_restore(state); printf("No messages or no message queue\n"); return; } + cib_t *msg_queue = &thread->msg_queue; - msg_t *msg_array = thread->msg_array; - int first_msg = cib_peek(msg_queue); + + /* copy message queue information to stack + before re-enabling IRQs (needed for highlevel_stdio) */ + unsigned size = msg_queue->mask + 1; + unsigned msg_count_print = MIN(msg_count, CONFIG_MSG_QUEUE_PRINT_MAX); + int msg_idx_first = cib_peek(msg_queue); + int msg_idx_last = (msg_idx_first + msg_count) & msg_queue->mask; + unsigned msg_count_to_end = size - msg_idx_first; + + static msg_t msg_array[CONFIG_MSG_QUEUE_PRINT_MAX]; + if (msg_idx_last > msg_idx_first || msg_count_to_end > msg_count_print) { + memcpy(msg_array, &thread->msg_array[msg_idx_first], + sizeof(msg_t) * (msg_count_print)); + } + else { + unsigned msg_count_from_start = MIN((unsigned)(msg_idx_last + 1), + msg_count_print - msg_count_to_end); + memcpy(&msg_array[0], &thread->msg_array[msg_idx_first], + sizeof(msg_t) * msg_count_to_end); + memcpy(&msg_array[msg_count_to_end], &thread->msg_array[0], + sizeof(msg_t) * msg_count_from_start); + } + irq_restore(state); printf("Message queue of thread %" PRIkernel_pid "\n", thread->pid); - printf(" size: %u (avail: %u)\n", msg_queue->mask + 1, msg_counter); + printf(" size: %u (avail: %u)\n", size, msg_count); - for (unsigned i = 0; i < msg_counter; i++) { - msg_t *m = &msg_array[(first_msg + i) & msg_queue->mask]; - printf(" * %u: sender: %" PRIkernel_pid ", type: 0x%04" PRIu16 + for (unsigned i = 0; i < msg_count_print; i++) { + msg_t *m = &msg_array[i]; + printf(" * %u: sender: %" PRIkernel_pid ", type: 0x%04" PRIx16 ", content: %" PRIu32 " (%p)\n", i, m->sender_pid, m->type, m->content.value, m->content.ptr); } - irq_restore(state); + if (msg_count > msg_count_print) { + puts(" ... (print more by changing CONFIG_MSG_QUEUE_PRINT_MAX)"); + } } diff --git a/tests/core/msg_queue_print/Makefile b/tests/core/msg_queue_print/Makefile index f4e5bc0fb4..55fbdf22d2 100644 --- a/tests/core/msg_queue_print/Makefile +++ b/tests/core/msg_queue_print/Makefile @@ -1,3 +1,10 @@ include ../Makefile.core_common +CONFIG_MSG_QUEUE_PRINT_MAX ?= 6 + +CFLAGS += -DCONFIG_MSG_QUEUE_PRINT_MAX=$(CONFIG_MSG_QUEUE_PRINT_MAX) + include $(RIOTBASE)/Makefile.include + +# Make config available in Python test script via environment variables +export CONFIG_MSG_QUEUE_PRINT_MAX diff --git a/tests/core/msg_queue_print/main.c b/tests/core/msg_queue_print/main.c index f52ee7dede..40aec733f5 100644 --- a/tests/core/msg_queue_print/main.c +++ b/tests/core/msg_queue_print/main.c @@ -1,5 +1,6 @@ /* - * Copyright (C) 2021 Freie Universität Berlin, + * Copyright (C) 2021 Freie Universität Berlin + * Copyright (C) 2024 TU Dresden * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -15,6 +16,7 @@ * * * @author Julian Holzwarth + * @author Mikolai Gütschow * */ @@ -29,19 +31,37 @@ msg_t msg_queue[QUEUE_SIZE]; int main(void) { - msg_t messages[QUEUE_SIZE]; + msg_t msg; msg_queue_print(); msg_init_queue(msg_queue, QUEUE_SIZE); msg_queue_print(); + /* fill message queue */ for (uintptr_t i = 0; i < QUEUE_SIZE; i++) { - messages[i].type = i; - messages[i].content.ptr = (void *) i; - msg_send_to_self(&messages[i]); + msg.type = i; + msg.content.ptr = (void *) i; + msg_send_to_self(&msg); } msg_queue_print(); + + /* drain half of message queue */ + for (uintptr_t i = 0; i < QUEUE_SIZE/2; i++) { + msg_receive(&msg); + } + + msg_queue_print(); + + /* fill up message queue again */ + for (uintptr_t i = QUEUE_SIZE; i < QUEUE_SIZE + QUEUE_SIZE/2; i++) { + msg.type = i; + msg.content.ptr = (void *) i; + msg_send_to_self(&msg); + } + + msg_queue_print(); + puts("DONE"); return 0; } diff --git a/tests/core/msg_queue_print/tests/01-run.py b/tests/core/msg_queue_print/tests/01-run.py index 2fa59ddff0..8bcb0c628e 100755 --- a/tests/core/msg_queue_print/tests/01-run.py +++ b/tests/core/msg_queue_print/tests/01-run.py @@ -1,34 +1,60 @@ #!/usr/bin/env python3 -# Copyright (C) 2021 Freie Universität Berlin, +# Copyright (C) 2021 Freie Universität Berlin +# Copyright (C) 2024 TU Dresden # # This file is subject to the terms and conditions of the GNU Lesser # General Public License v2.1. See the file LICENSE in the top level # directory for more details. # @author Julian Holzwarth +# @author Mikolai Gütschow import os import sys from testrunner import run +PRINT_MAX = int(os.getenv('CONFIG_MSG_QUEUE_PRINT_MAX')) + + +def expect_none(child): + child.expect("No messages or no message queue") + + +def expect_some(child, size, avail, range_start): + child.expect(r"Message queue of thread \d+\r\n") + child.expect_exact(f'size: {size} (avail: {avail})') + + expect_less = avail > PRINT_MAX + + if expect_less: + range_end = range_start + PRINT_MAX + else: + range_end = range_start + avail + + for counter in range(range_start, range_end): + expect_content(child, counter) + + if expect_less: + child.expect('...') + + +def expect_content(child, counter): + if counter == 0: + if os.environ.get('BOARD') in ['native', 'native64']: + child.expect_exact('type: 0x0000, content: 0 ((nil))') + else: + child.expect(r'type: 0x0000, content: 0 \((0x)?0+\)') + else: + child.expect_exact(f'type: 0x{counter:04x}, content: {counter} (0x{counter:x})') + def testfunc(child): - child.expect("No messages or no message queue") - child.expect("No messages or no message queue") - child.expect(r"Message queue of thread \d+\r\n") - child.expect_exact('size: 8 (avail: 8)') - if os.environ.get('BOARD') in ['native', 'native64']: - child.expect_exact('type: 0x0000, content: 0 ((nil))') - else: - child.expect(r'type: 0x0000, content: 0 \((0x)?0+\)') - child.expect_exact('type: 0x0001, content: 1 (0x1)') - child.expect_exact('type: 0x0002, content: 2 (0x2)') - child.expect_exact('type: 0x0003, content: 3 (0x3)') - child.expect_exact('type: 0x0004, content: 4 (0x4)') - child.expect_exact('type: 0x0005, content: 5 (0x5)') - child.expect_exact('type: 0x0006, content: 6 (0x6)') - child.expect_exact('type: 0x0007, content: 7 (0x7)') + expect_none(child) + expect_none(child) + expect_some(child, 8, 8, 0) + expect_some(child, 8, 4, 4) + expect_some(child, 8, 8, 4) child.expect_exact('DONE')