diff --git a/tests/irq_disable_restore/Makefile b/tests/irq_disable_restore/Makefile new file mode 100644 index 0000000000..b44722f60f --- /dev/null +++ b/tests/irq_disable_restore/Makefile @@ -0,0 +1,6 @@ +include ../Makefile.tests_common + +USEMODULE += fmt +USEMODULE += xtimer + +include $(RIOTBASE)/Makefile.include diff --git a/tests/irq_disable_restore/README.md b/tests/irq_disable_restore/README.md new file mode 100644 index 0000000000..16f385da2f --- /dev/null +++ b/tests/irq_disable_restore/README.md @@ -0,0 +1,13 @@ +# Test for `irq_disable()` and `irq_restore()` + +This test checks if `irq_disable()` and `irq_restore()` work as intended. For +that, the test uses two variables *a* and *b*, both initialized with 0. The main +test will schedule a timer that expires in *T/2*. It will then set *a* to 1 and +waits for *T* until it also sets *b* to one. The expectation is that during the +ISR (the timer callback) *a* has a value of 1, but *b* still has a value of 0. + +The test is repeated, but this time the main thread calls `irq_disable()` +before setting *a* and `irq_restore()` after setting *b*. It is now expected +that - even though the timer again expires after setting *a* and before setting +*b* - the execution of the ISR is delayed until `irq_restore()` is called. Thus, +both *a* and *b* should already contain the new value in the ISR. diff --git a/tests/irq_disable_restore/main.c b/tests/irq_disable_restore/main.c new file mode 100644 index 0000000000..c140ef0b63 --- /dev/null +++ b/tests/irq_disable_restore/main.c @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2020 Otto-von-Guericke-Universität Magdeburg + * + * 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 irq_disable_restore test application + * + * @author Marian Buschsieweke + * @} + */ + +#include +#include +#include + +#include "fmt.h" +#include "irq.h" +#include "xtimer.h" + +#define DELAY (10 * US_PER_MS) + +static atomic_uint a = ATOMIC_VAR_INIT(0); +static atomic_uint a_during_isr = ATOMIC_VAR_INIT(0); +static atomic_uint b = ATOMIC_VAR_INIT(0); +static atomic_uint b_during_isr = ATOMIC_VAR_INIT(0); + +static void busy_delay(void) +{ + uint32_t start = xtimer_now_usec(); + while (xtimer_now_usec() - start < DELAY) { } +} + +/* Timer callback run in interrupt context; should not trigger between + * irq_disable() and irq_restore() + */ +static void timer_callback(void *unused) +{ + (void)unused; + atomic_store(&a_during_isr, atomic_load(&a)); + atomic_store(&b_during_isr, atomic_load(&b)); +} + +int main(void) +{ + xtimer_t xt = { .callback = timer_callback }; + + print_str("Test for irq_disable() / irq_restore()\n" + "======================================\n" + "\n"); + + print_str("Verifying test works: "); + xtimer_set(&xt, DELAY / 2); + atomic_store(&a, 1); + busy_delay(); + atomic_store(&b, 1); + + /* Timer should have fired in the middle of busy_delay(), thus value of + * a now and during ISR should both be 1, but value of b during ISR should + * still be 0 but not it should be 1 */ + if ((atomic_load(&a) == atomic_load(&a_during_isr)) && + (atomic_load(&b) != atomic_load(&b_during_isr))) + { + print_str("[SUCCESS]\n"); + } + else { + print_str("[FAILURE]\n"); + } + + print_str("Test result: "); + xtimer_set(&xt, DELAY / 2); + unsigned state = irq_disable(); + atomic_store(&a, 2); + busy_delay(); + atomic_store(&b, 2); + irq_restore(state); + + /* irq_disable() should have delayed execution of the timer until both + * a and b have been set to 2. + */ + + if ((atomic_load(&a) == atomic_load(&a_during_isr)) && + (atomic_load(&b) == atomic_load(&b_during_isr))) + { + print_str("[SUCCESS]\n"); + } + else { + print_str("[FAILURE]\n"); + } + + return 0; +} diff --git a/tests/irq_disable_restore/tests/01-run.py b/tests/irq_disable_restore/tests/01-run.py new file mode 100755 index 0000000000..71d86b47d1 --- /dev/null +++ b/tests/irq_disable_restore/tests/01-run.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 + +# Copyright (C) 2020 Otto-von-Guericke-Universität Magdeburg +# +# 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 + + +def testfunc(child): + child.expect_exact("Verifying test works: [SUCCESS]") + child.expect_exact("Test result: [SUCCESS]") + + +if __name__ == "__main__": + sys.exit(run(testfunc))