Skip to content

Commit

Permalink
Merge pull request #10908 from miri64/tests/new/i10881
Browse files Browse the repository at this point in the history
tests: add tests to reproduce #10881
  • Loading branch information
miri64 authored Mar 28, 2019
2 parents ef2b33c + 3b95ac0 commit 7220ed2
Show file tree
Hide file tree
Showing 3 changed files with 150 additions and 0 deletions.
14 changes: 14 additions & 0 deletions tests/thread_msg_block_race/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
DEVELHELP := 1

include ../Makefile.tests_common

BOARD_INSUFFICIENT_MEMORY := arduino-duemilanove arduino-nano arduino-uno \
nucleo-f031k6

DISABLE_MODULE += auto_init
FEATURES_REQUIRED += periph_timer
USEMODULE += random

TEST_ON_CI_WHITELIST += all

include $(RIOTBASE)/Makefile.include
114 changes: 114 additions & 0 deletions tests/thread_msg_block_race/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/*
* Copyright (C) 2019 Freie Universität Berlin
*
* 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.
*/

/**
* @ingroup tests
* @{
*
* @file
* @brief Thread race condition test application to reproduce
* https://github.com/RIOT-OS/RIOT/issues/10881
*
* @author Martine Lenders <[email protected]>
*
* @}
*/

#include <stdio.h>
#include <unistd.h>

#include "periph/timer.h"
#include "random.h"
#include "thread.h"
#include "msg.h"

#define CANARY_TYPE (0x21fd)

#define TIMER_FREQ (1000000LU)
#define TIMER_TIMEOUT_MIN (1U)
#define TIMER_TIMEOUT_MAX (100U)

static char _stack[THREAD_STACKSIZE_DEFAULT];

static kernel_pid_t _pid_main = KERNEL_PID_UNDEF;

/**
* @brief Schedule next timer event in TIMER_TIMEOUT_MIN to TIMER_TIMEOUT_MAX
* ticks.
*/
static void _sched_next(void)
{
timer_set(TIMER_DEV(0), 0, random_uint32_range(TIMER_TIMEOUT_MIN,
TIMER_TIMEOUT_MAX));
}

/**
* @brief The timer interrupt
*/
static void _timer(void *arg, int channel)
{
(void)arg;
(void)channel;
/* just continue rescheduling interrupt triggering at random time */
_sched_next();
}

/**
* @brief The sending thread
*/
static void *_thread(void *arg)
{
(void) arg;

while (1) {
msg_t msg = { .type = 0U };

write(STDOUT_FILENO, ".", 1U);
/* send without blocking */
msg_try_send(&msg, _pid_main);
thread_yield();
}

return NULL;
}

int main(void)
{
kernel_pid_t pid;

timer_init(TIMER_DEV(0), TIMER_FREQ, _timer, NULL);
random_init(timer_read(TIMER_DEV(0)));
puts("Test is \"successful\" if it runs forever without halting\n"
"on any of the assertion in this file\n");
_pid_main = sched_active_pid;

puts("I will try to trigger an interrupt at random intervals. When an\n"
"interrupt is fired while ISR is disable in the thread_yield_higher()\n"
"function some platform-specific implementations used to not call\n"
"sched_run() which was the cause of the bug tested here");
_sched_next();
pid = thread_create(_stack, sizeof(_stack), THREAD_PRIORITY_MAIN + 1,
THREAD_CREATE_WOUT_YIELD | THREAD_CREATE_STACKTEST,
_thread, NULL, "nr2");
assert(pid != KERNEL_PID_UNDEF);

while (1) {
msg_t msg = { .type = CANARY_TYPE };

/* receive blocked */
msg_receive(&msg);
/* check msg_receive() returned without blocking (i.e. the sending
* thread did not get a chance to copy the message over) */
if (msg.type == CANARY_TYPE) {
puts("Message was not written");
return 1;
}
write(STDOUT_FILENO, "\b", 1U);
}
return 0;
}
22 changes: 22 additions & 0 deletions tests/thread_msg_block_race/tests/01-run.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/env python3

# Copyright (C) 2019 Freie Universität Berlin
#
# 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 sys
from testrunner import run
from pexpect import TIMEOUT


def testfunc(child):
res = child.expect([TIMEOUT, "Message was not written"])
# we actually want the timeout here. The application runs into an assertion
# pretty quickly when failing and runs forever on success
assert(res == 0)


if __name__ == "__main__":
sys.exit(run(testfunc, timeout=10))

0 comments on commit 7220ed2

Please sign in to comment.