diff --git a/tests/thread_msg_block_w_queue/Makefile b/tests/thread_msg_block_w_queue/Makefile index 5f37154536..518172d659 100644 --- a/tests/thread_msg_block_w_queue/Makefile +++ b/tests/thread_msg_block_w_queue/Makefile @@ -6,3 +6,8 @@ BOARD_INSUFFICIENT_MEMORY := nucleo32-f031 DISABLE_MODULE += auto_init include $(RIOTBASE)/Makefile.include + +test: +# `testrunner` calls `make term` recursively, results in duplicated `TERMFLAGS`. +# So clears `TERMFLAGS` before run. + TERMFLAGS= tests/01-run.py diff --git a/tests/thread_msg_block_w_queue/README.md b/tests/thread_msg_block_w_queue/README.md new file mode 100644 index 0000000000..b2bbb7cec8 --- /dev/null +++ b/tests/thread_msg_block_w_queue/README.md @@ -0,0 +1,22 @@ +Background +========== +This test application checks for the behavior reported in https://github.com/RIOT-OS/RIOT/issues/100: + +Usually, when a thread (here `sender_thread`) sends a message to another thread (here the `main` thread) whose message queue already holds a message, the message of `sender_thread` is copied into `main`'s message queue and `sender_thread` is set to `STATUS_PENDING`. However, this should *not* happen if `sender_thread` is currently in `STATUS_REPLY_BLOCKED` mode, since it is in the middle of a different, blocking send. + +In the aforementioned issue, it was reported that this undesired behavior was happening. It has been fixed since, and this test ensures that it doesn't re-occur again. + +Expected result +=============== +The output should look as follows: + +``` +sender_thread start +main thread alive +``` + +If you see +``` +ERROR: sender_thread should be blocking +``` +something went wrong. \ No newline at end of file diff --git a/tests/thread_msg_block_w_queue/main.c b/tests/thread_msg_block_w_queue/main.c index 6e6617a5d5..cd1245d94a 100644 --- a/tests/thread_msg_block_w_queue/main.c +++ b/tests/thread_msg_block_w_queue/main.c @@ -27,26 +27,27 @@ char t1_stack[THREAD_STACKSIZE_MAIN]; -kernel_pid_t p1 = KERNEL_PID_UNDEF, p_main = KERNEL_PID_UNDEF; +kernel_pid_t p_send = KERNEL_PID_UNDEF, p_recv = KERNEL_PID_UNDEF; -void *thread1(void *arg) +void *sender_thread(void *arg) { (void) arg; - printf("THREAD %" PRIkernel_pid " start\n", p1); + printf("sender_thread start\n"); msg_t msg, reply; memset(&msg, 1, sizeof(msg_t)); - /* step 1: send asynchonously */ - msg_try_send(&msg, p_main); + /* step 1: send non-blocking to fill up the msg_queue of p_recv */ + msg_try_send(&msg, p_recv); - /* step 2: send message, turning its status into STATUS_REPLY_BLOCKED */ - msg_send_receive(&msg, &reply, p_main); - printf("received: %" PRIkernel_pid ", %u \n", reply.sender_pid, reply.type); - printf("pointer: %s\n", (char *)reply.content.ptr); + /* step 2: send message. This puts sender_thread into msg_waiters and turns its + status into STATUS_REPLY_BLOCKED. It should block forever, since the + second message is never read by p_recv. */ + msg_send_receive(&msg, &reply, p_recv); - printf("THREAD %" PRIkernel_pid " SHOULD BE BLOCKING :(\n", p1); + /* If this is printed, sender_thread did *not* block as expected. */ + printf("ERROR: sender_thread should be blocking\n"); return NULL; } @@ -54,18 +55,19 @@ void *thread1(void *arg) int main(void) { msg_t msg; - p_main = sched_active_pid; + p_recv = sched_active_pid; msg_t msg_q[1]; msg_init_queue(msg_q, 1); - p1 = thread_create(t1_stack, sizeof(t1_stack), THREAD_PRIORITY_MAIN - 1, + p_send = thread_create(t1_stack, sizeof(t1_stack), THREAD_PRIORITY_MAIN - 1, THREAD_CREATE_WOUT_YIELD | THREAD_CREATE_STACKTEST, - thread1, NULL, "nr1"); + sender_thread, NULL, "nr1"); - /* step 3: receive a msg */ + /* step 3: receive first msg from sender_thread*/ msg_receive(&msg); - printf("MAIN THREAD %" PRIkernel_pid " ALIVE!\n", p_main); + printf("main thread alive\n"); + return 0; } diff --git a/tests/thread_msg_block_w_queue/tests/01-run.py b/tests/thread_msg_block_w_queue/tests/01-run.py new file mode 100755 index 0000000000..69f13d11d4 --- /dev/null +++ b/tests/thread_msg_block_w_queue/tests/01-run.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python3 + +# Copyright (C) 2017 Lotte Steenbrink +# +# 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. + +import os +import sys + +sys.path.append(os.path.join(os.environ['RIOTBASE'], 'dist/tools/testrunner')) +import testrunner + +def testfunc(child): + child.expect('sender_thread start\r\n') + child.expect('main thread alive\r\n') + +if __name__ == "__main__": + sys.exit(testrunner.run(testfunc))