[PATCH 16/33] libtest: Add T_interrupt_test()
Sebastian Huber
sebastian.huber at embedded-brains.de
Tue Jul 21 15:04:33 UTC 2020
Update #3199.
---
cpukit/Makefile.am | 1 +
cpukit/include/rtems/test.h | 28 ++
cpukit/libtest/t-test-interrupt.c | 420 ++++++++++++++++++++++++
testsuites/libtests/Makefile.am | 9 +
testsuites/libtests/configure.ac | 1 +
testsuites/libtests/ttest02/init.c | 176 ++++++++++
testsuites/libtests/ttest02/ttest02.doc | 11 +
testsuites/libtests/ttest02/ttest02.scn | 37 +++
8 files changed, 683 insertions(+)
create mode 100644 cpukit/libtest/t-test-interrupt.c
create mode 100644 testsuites/libtests/ttest02/init.c
create mode 100644 testsuites/libtests/ttest02/ttest02.doc
create mode 100644 testsuites/libtests/ttest02/ttest02.scn
diff --git a/cpukit/Makefile.am b/cpukit/Makefile.am
index 89edaefb17..75e119ea3c 100644
--- a/cpukit/Makefile.am
+++ b/cpukit/Makefile.am
@@ -1864,6 +1864,7 @@ librtemstest_a_SOURCES += libtest/t-test-checks.c
librtemstest_a_SOURCES += libtest/t-test-checks-eno.c
librtemstest_a_SOURCES += libtest/t-test-checks-psx.c
librtemstest_a_SOURCES += libtest/t-test-hash-sha256.c
+librtemstest_a_SOURCES += libtest/t-test-interrupt.c
librtemstest_a_SOURCES += libtest/t-test-malloc.c
librtemstest_a_SOURCES += libtest/t-test-rtems.c
librtemstest_a_SOURCES += libtest/t-test-rtems-context.c
diff --git a/cpukit/include/rtems/test.h b/cpukit/include/rtems/test.h
index 5d4c676d16..628efcb505 100644
--- a/cpukit/include/rtems/test.h
+++ b/cpukit/include/rtems/test.h
@@ -2360,6 +2360,34 @@ void T_busy(uint_fast32_t);
uint_fast32_t T_get_one_clock_tick_busy(void);
+typedef enum {
+ T_INTERRUPT_TEST_INITIAL,
+ T_INTERRUPT_TEST_ACTION,
+ T_INTERRUPT_TEST_BLOCKED,
+ T_INTERRUPT_TEST_CONTINUE,
+ T_INTERRUPT_TEST_DONE,
+ T_INTERRUPT_TEST_EARLY,
+ T_INTERRUPT_TEST_INTERRUPT,
+ T_INTERRUPT_TEST_LATE,
+ T_INTERRUPT_TEST_TIMEOUT
+} T_interrupt_test_state;
+
+typedef struct {
+ void (*prepare)(void *);
+ void (*action)(void *);
+ T_interrupt_test_state (*interrupt)(void *);
+ void (*blocked)(void *);
+ uint32_t max_iteration_count;
+} T_interrupt_test_config;
+
+T_interrupt_test_state T_interrupt_test_change_state(T_interrupt_test_state,
+ T_interrupt_test_state);
+
+T_interrupt_test_state T_interrupt_test_get_state(void);
+
+T_interrupt_test_state T_interrupt_test(const T_interrupt_test_config *config,
+ void *arg);
+
void T_report_hash_sha256(T_event, const char *);
void T_check_heap(T_event, const char *);
diff --git a/cpukit/libtest/t-test-interrupt.c b/cpukit/libtest/t-test-interrupt.c
new file mode 100644
index 0000000000..f97369105f
--- /dev/null
+++ b/cpukit/libtest/t-test-interrupt.c
@@ -0,0 +1,420 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/**
+ * @file
+ *
+ * @ingroup RTEMSTestFrameworkImpl
+ *
+ * @brief Implementation of T_interrupt_test().
+ */
+
+/*
+ * Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <rtems/test.h>
+
+#include <rtems/score/atomic.h>
+#include <rtems/score/percpu.h>
+#include <rtems/score/thread.h>
+#include <rtems/score/timecounter.h>
+#include <rtems/score/timestampimpl.h>
+#include <rtems/score/userextimpl.h>
+#include <rtems/score/watchdogimpl.h>
+
+typedef T_interrupt_test_state (*T_interrupt_test_handler)(void *);
+
+#define T_INTERRUPT_SAMPLE_COUNT 8
+
+typedef struct {
+ uint_fast32_t one_tick_busy;
+ int64_t t0;
+ Thread_Control *self;
+ Atomic_Uint state;
+ void (*prepare)(void *);
+ void (*action)(void *);
+ T_interrupt_test_state (*interrupt)(void *);
+ void (*blocked)(void *);
+ void *arg;
+ Watchdog_Control wdg;
+ User_extensions_Control ext;
+ T_fixture_node node;
+} T_interrupt_context;
+
+typedef struct {
+ int64_t t;
+ int64_t d;
+} T_interrupt_clock_time;
+
+static void
+T_interrupt_sort(T_interrupt_clock_time *ct, size_t n)
+{
+ size_t i;
+
+ /* Bubble sort */
+ for (i = 1; i < n ; ++i) {
+ size_t j;
+
+ for (j = 0; j < n - i; ++j) {
+ if (ct[j].d > ct[j + 1].d) {
+ T_interrupt_clock_time tmp;
+
+ tmp = ct[j];
+ ct[j] = ct[j + 1];
+ ct[j + 1] = tmp;
+ }
+ }
+ }
+}
+
+static int64_t
+T_interrupt_time_close_to_tick(void)
+{
+ Watchdog_Interval c0;
+ Watchdog_Interval c1;
+ T_interrupt_clock_time ct[12];
+ Timestamp_Control t;
+ int32_t ns_per_tick;
+ size_t i;
+ size_t n;
+
+ ns_per_tick = (int32_t)_Watchdog_Nanoseconds_per_tick;
+ n = RTEMS_ARRAY_SIZE(ct);
+ c0 = _Watchdog_Ticks_since_boot;
+
+ for (i = 0; i < n; ++i) {
+ do {
+ c1 = _Watchdog_Ticks_since_boot;
+ t = _Timecounter_Sbinuptime();
+ } while (c0 == c1);
+
+ c0 = c1;
+ ct[i].t = sbttons(t);
+ }
+
+ for (i = 1; i < n; ++i) {
+ int64_t d;
+
+ d = (ct[i].t - ct[1].t) % ns_per_tick;
+
+ if (d > ns_per_tick / 2) {
+ d -= ns_per_tick;
+ }
+
+ ct[i].d = d;
+ }
+
+ /*
+ * Use the median and not the arithmetic mean since on simulator
+ * platforms there may be outliers.
+ */
+ T_interrupt_sort(&ct[1], n - 1);
+ return ct[1 + (n - 1) / 2].t;
+}
+
+static void
+T_interrupt_watchdog(Watchdog_Control *wdg)
+{
+ T_interrupt_context *ctx;
+ ISR_Level level;
+ T_interrupt_test_state state;
+ unsigned int expected;
+
+ ctx = RTEMS_CONTAINER_OF(wdg, T_interrupt_context, wdg);
+
+ _ISR_Local_disable(level);
+ _Watchdog_Per_CPU_insert_ticks(&ctx->wdg,
+ _Watchdog_Get_CPU(&ctx->wdg), 1);
+ _ISR_Local_enable(level);
+
+ state = (*ctx->interrupt)(ctx->arg);
+
+ expected = T_INTERRUPT_TEST_ACTION;
+ _Atomic_Compare_exchange_uint(&ctx->state, &expected,
+ state, ATOMIC_ORDER_RELAXED, ATOMIC_ORDER_RELAXED);
+}
+
+static void
+T_interrupt_watchdog_insert(T_interrupt_context *ctx)
+{
+ ISR_Level level;
+
+ _ISR_Local_disable(level);
+ _Watchdog_Per_CPU_insert_ticks(&ctx->wdg, _Per_CPU_Get(), 1);
+ _ISR_Local_enable(level);
+}
+
+static void
+T_interrupt_watchdog_remove(T_interrupt_context *ctx)
+{
+ ISR_Level level;
+
+ _ISR_Local_disable(level);
+ _Watchdog_Per_CPU_remove_ticks(&ctx->wdg);
+ _ISR_Local_enable(level);
+}
+
+static void
+T_interrupt_init_once(T_interrupt_context *ctx)
+{
+ ctx->t0 = T_interrupt_time_close_to_tick();
+ ctx->one_tick_busy = T_get_one_clock_tick_busy();
+}
+
+static T_interrupt_test_state
+T_interrupt_continue(void *arg)
+{
+ (void)arg;
+ return T_INTERRUPT_TEST_CONTINUE;
+}
+
+static void
+T_interrupt_do_nothing(void *arg)
+{
+ (void)arg;
+}
+
+static void T_interrupt_thread_switch(Thread_Control *, Thread_Control *);
+
+static T_interrupt_context T_interrupt_instance = {
+ .interrupt = T_interrupt_continue,
+ .blocked = T_interrupt_do_nothing,
+ .wdg = WATCHDOG_INITIALIZER(T_interrupt_watchdog),
+ .ext = {
+ .Callouts = {
+ .thread_switch = T_interrupt_thread_switch
+ }
+ }
+};
+
+T_interrupt_test_state
+T_interrupt_test_change_state(T_interrupt_test_state expected_state,
+ T_interrupt_test_state desired_state)
+{
+ T_interrupt_context *ctx;
+ unsigned int expected;
+
+ ctx = &T_interrupt_instance;
+ expected = expected_state;
+ _Atomic_Compare_exchange_uint(&ctx->state, &expected,
+ desired_state, ATOMIC_ORDER_RELAXED, ATOMIC_ORDER_RELAXED);
+
+ return expected;
+}
+
+T_interrupt_test_state
+T_interrupt_test_get_state(void)
+{
+ T_interrupt_context *ctx;
+
+ ctx = &T_interrupt_instance;
+ return _Atomic_Load_uint(&ctx->state, ATOMIC_ORDER_RELAXED);
+}
+
+static void
+T_interrupt_thread_switch(Thread_Control *executing, Thread_Control *heir)
+{
+ T_interrupt_context *ctx;
+
+ (void)heir;
+ ctx = &T_interrupt_instance;
+
+ if (ctx->self == executing) {
+ T_interrupt_test_state state;
+
+ state = _Atomic_Load_uint(&ctx->state, ATOMIC_ORDER_RELAXED);
+
+ if (state != T_INTERRUPT_TEST_INITIAL) {
+ (*ctx->blocked)(ctx->arg);
+ }
+ }
+}
+
+static T_interrupt_context *
+T_interrupt_setup(const T_interrupt_test_config *config, void *arg)
+{
+ T_interrupt_context *ctx;
+
+ T_quiet_assert_not_null(config->action);
+ T_quiet_assert_not_null(config->interrupt);
+ ctx = &T_interrupt_instance;
+ ctx->self = _Thread_Get_executing();
+ ctx->arg = arg;
+ ctx->interrupt = config->interrupt;
+
+ if (config->blocked != NULL) {
+ ctx->blocked = config->blocked;
+ }
+
+ if (ctx->t0 == 0) {
+ T_interrupt_init_once(ctx);
+ }
+
+ _User_extensions_Add_set(&ctx->ext);
+ T_interrupt_watchdog_insert(ctx);
+ return ctx;
+}
+
+static void
+T_interrupt_teardown(void *arg)
+{
+ T_interrupt_context *ctx;
+
+ ctx = arg;
+ ctx->interrupt = T_interrupt_continue;
+ ctx->blocked = T_interrupt_do_nothing;
+ T_interrupt_watchdog_remove(ctx);
+ _User_extensions_Remove_set(&ctx->ext);
+ ctx->self = NULL;
+ ctx->arg = NULL;
+}
+
+static T_fixture T_interrupt_fixture = {
+ .teardown = T_interrupt_teardown,
+ .initial_context = &T_interrupt_instance
+};
+
+T_interrupt_test_state
+T_interrupt_test(const T_interrupt_test_config *config, void *arg)
+{
+ T_interrupt_context *ctx;
+ uint_fast32_t lower_bound[T_INTERRUPT_SAMPLE_COUNT];
+ uint_fast32_t upper_bound[T_INTERRUPT_SAMPLE_COUNT];
+ uint_fast32_t lower_sum;
+ uint_fast32_t upper_sum;
+ int32_t ns_per_tick;
+ size_t sample;
+ uint32_t iter;
+
+ ctx = T_interrupt_setup(config, arg);
+ T_push_fixture(&ctx->node, &T_interrupt_fixture);
+ ns_per_tick = (int32_t)_Watchdog_Nanoseconds_per_tick;
+ lower_sum = 0;
+ upper_sum = T_INTERRUPT_SAMPLE_COUNT * ctx->one_tick_busy;
+
+ for (sample = 0; sample < T_INTERRUPT_SAMPLE_COUNT; ++sample) {
+ lower_bound[sample] = 0;
+ upper_bound[sample] = ctx->one_tick_busy;
+ }
+
+ sample = 0;
+
+ for (iter = 0; iter < config->max_iteration_count; ++iter) {
+ T_interrupt_test_state state;
+ int64_t t;
+ int64_t d;
+ Timestamp_Control s1;
+ Timestamp_Control s0;
+ uint_fast32_t busy;
+ uint_fast32_t delta;
+
+ if (config->prepare != NULL) {
+ (*config->prepare)(arg);
+ }
+
+ /*
+ * We use some sort of a damped bisection to find the right
+ * interrupt time point.
+ */
+ busy = (lower_sum + upper_sum) /
+ (2 * T_INTERRUPT_SAMPLE_COUNT);
+
+ t = sbttons(_Timecounter_Sbinuptime());
+ d = (t - ctx->t0) % ns_per_tick;
+ t += ns_per_tick / 4 - d;
+
+ if (d > ns_per_tick / 8) {
+ t += ns_per_tick;
+ }
+
+ /*
+ * The s1 value is a future time point close to 25% of a clock
+ * tick interval.
+ */
+ s1 = nstosbt(t);
+
+ /*
+ * The path from here to the action call must avoid anything
+ * which can cause jitters. We wait until 25% of the clock
+ * tick interval are elapsed using the timecounter. Then we do
+ * a busy wait and call the action. The interrupt time point
+ * is controlled by the busy count.
+ */
+
+ do {
+ s0 = _Timecounter_Sbinuptime();
+ } while (s0 < s1);
+
+ _Atomic_Store_uint(&ctx->state, T_INTERRUPT_TEST_ACTION,
+ ATOMIC_ORDER_RELAXED);
+ T_busy(busy);
+ (*config->action)(arg);
+
+ state = _Atomic_Exchange_uint(&ctx->state,
+ T_INTERRUPT_TEST_INITIAL, ATOMIC_ORDER_RELAXED);
+
+ if (state == T_INTERRUPT_TEST_DONE) {
+ break;
+ }
+
+ /* Adjust the lower/upper bound of the bisection interval */
+ if (state == T_INTERRUPT_TEST_EARLY) {
+ uint_fast32_t lower;
+
+ upper_sum -= upper_bound[sample];
+ upper_sum += busy;
+ upper_bound[sample] = busy;
+
+ lower = lower_bound[sample];
+ delta = (lower + 31) / 32;
+ lower_sum -= delta;
+ lower_bound[sample] = lower - delta;
+ } else if (state == T_INTERRUPT_TEST_LATE) {
+ uint_fast32_t upper;
+
+ lower_sum -= lower_bound[sample];
+ lower_sum += busy;
+ lower_bound[sample] = busy;
+
+ upper = upper_bound[sample];
+ delta = (upper + 31) / 32;
+ upper_sum += delta;
+ upper_bound[sample] = upper + delta;
+ }
+
+ sample = (sample + 1) % T_INTERRUPT_SAMPLE_COUNT;
+ }
+
+ T_pop_fixture();
+
+ if (iter == config->max_iteration_count) {
+ return T_INTERRUPT_TEST_TIMEOUT;
+ }
+
+ return T_INTERRUPT_TEST_DONE;
+}
diff --git a/testsuites/libtests/Makefile.am b/testsuites/libtests/Makefile.am
index c312f14324..2ff05f2b74 100644
--- a/testsuites/libtests/Makefile.am
+++ b/testsuites/libtests/Makefile.am
@@ -1493,6 +1493,15 @@ ttest01_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_FLAGS_ttest01) \
$(support_includes)
endif
+if TEST_ttest02
+lib_tests += ttest02
+lib_screens += ttest02/ttest02.scn
+lib_docs += ttest02/ttest02.doc
+ttest02_SOURCES = ttest02/init.c
+ttest02_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_FLAGS_ttest02) \
+ $(support_includes)
+endif
+
if TEST_tztest
lib_tests += tztest
lib_screens += tztest/tztest.scn
diff --git a/testsuites/libtests/configure.ac b/testsuites/libtests/configure.ac
index 3b5462600d..2fbcb61622 100644
--- a/testsuites/libtests/configure.ac
+++ b/testsuites/libtests/configure.ac
@@ -225,6 +225,7 @@ RTEMS_TEST_CHECK([termios10])
RTEMS_TEST_CHECK([termios11])
RTEMS_TEST_CHECK([top])
RTEMS_TEST_CHECK([ttest01])
+RTEMS_TEST_CHECK([ttest02])
RTEMS_TEST_CHECK([tztest])
RTEMS_TEST_CHECK([uid01])
RTEMS_TEST_CHECK([unlink])
diff --git a/testsuites/libtests/ttest02/init.c b/testsuites/libtests/ttest02/init.c
new file mode 100644
index 0000000000..8e9210109c
--- /dev/null
+++ b/testsuites/libtests/ttest02/init.c
@@ -0,0 +1,176 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/*
+ * Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <rtems/test.h>
+#include <rtems/simple-test.h>
+
+#include <rtems.h>
+
+static void
+prepare(void *arg)
+{
+ Atomic_Uint *state;
+
+ state = arg;
+ _Atomic_Store_uint(state, 0, ATOMIC_ORDER_RELAXED);
+}
+
+static void
+action(void *arg)
+{
+ Atomic_Uint *state;
+ unsigned int expected;
+ bool success_0;
+ bool success_1;
+
+ state = arg;
+
+ /*
+ * This code models a critical section in the operating system. The
+ * interrupt should happen between the two atomic operations.
+ */
+ expected = 0;
+ success_0 = _Atomic_Compare_exchange_uint(state, &expected, 1,
+ ATOMIC_ORDER_RELAXED, ATOMIC_ORDER_RELAXED);
+ expected = 1;
+ success_1 = _Atomic_Compare_exchange_uint(state, &expected, 2,
+ ATOMIC_ORDER_RELAXED, ATOMIC_ORDER_RELAXED);
+ T_quiet_true(success_0);
+ T_quiet_true(success_1);
+
+ while (T_interrupt_test_get_state() == T_INTERRUPT_TEST_ACTION) {
+ /* Wait */
+ }
+}
+
+static T_interrupt_test_state
+interrupt(void *arg)
+{
+ Atomic_Uint *state;
+ unsigned int expected;
+
+ if (T_interrupt_test_get_state() != T_INTERRUPT_TEST_ACTION) {
+ return T_INTERRUPT_TEST_CONTINUE;
+ }
+
+ state = arg;
+ expected = 1;
+
+ if (_Atomic_Compare_exchange_uint(state, &expected, expected,
+ ATOMIC_ORDER_RELAXED, ATOMIC_ORDER_RELAXED)) {
+ return T_INTERRUPT_TEST_DONE;
+ } else if (expected == 0) {
+ return T_INTERRUPT_TEST_EARLY;
+ } else {
+ T_quiet_eq_uint(expected, 2);
+ return T_INTERRUPT_TEST_LATE;
+ }
+}
+
+static const T_interrupt_test_config done_config = {
+ .prepare = prepare,
+ .action = action,
+ .interrupt = interrupt,
+ .max_iteration_count = 10000
+};
+
+T_TEST_CASE(TestInterruptDone)
+{
+ int i;
+
+ for (i = 0; i < 10; ++i) {
+ Atomic_Uint action_state;
+ T_interrupt_test_state state;
+
+ state = T_interrupt_test(&done_config, &action_state);
+ T_eq_int(state, T_INTERRUPT_TEST_DONE);
+ }
+}
+
+static const T_interrupt_test_config timeout_config = {
+ .interrupt = interrupt,
+ .action = action
+};
+
+T_TEST_CASE(TestInterruptTimeout)
+{
+ Atomic_Uint action_state;
+ T_interrupt_test_state state;
+
+ T_plan(1);
+ state = T_interrupt_test(&timeout_config, &action_state);
+ T_step_eq_int(0, state, T_INTERRUPT_TEST_TIMEOUT);
+}
+
+static void
+fatal(void *arg)
+{
+ (void)arg;
+ T_step(0);
+ T_stop();
+}
+
+static const T_interrupt_test_config fatal_config = {
+ .prepare = fatal,
+ .action = action,
+ .interrupt = interrupt,
+ .max_iteration_count = 10000
+};
+
+T_TEST_CASE(TestInterruptFatal)
+{
+ Atomic_Uint action_state;
+
+ T_plan(1);
+ T_interrupt_test(&fatal_config, &action_state);
+ T_unreachable();
+}
+
+const char rtems_test_name[] = "TTEST 2";
+
+static void
+Init(rtems_task_argument argument)
+{
+ rtems_test_run(argument, TEST_STATE);
+}
+
+#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
+#define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER
+
+#define CONFIGURE_MICROSECONDS_PER_TICK 1000
+
+#define CONFIGURE_MAXIMUM_TASKS 1
+
+#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
+
+#define CONFIGURE_INIT
+
+#include <rtems/confdefs.h>
diff --git a/testsuites/libtests/ttest02/ttest02.doc b/testsuites/libtests/ttest02/ttest02.doc
new file mode 100644
index 0000000000..193f288d71
--- /dev/null
+++ b/testsuites/libtests/ttest02/ttest02.doc
@@ -0,0 +1,11 @@
+This file describes the directives and concepts tested by this test set.
+
+test set name: ttest02
+
+directives:
+
+ - T_interrupt_test()
+
+concepts:
+
+ - Ensure that the interrupt test works.
diff --git a/testsuites/libtests/ttest02/ttest02.scn b/testsuites/libtests/ttest02/ttest02.scn
new file mode 100644
index 0000000000..7ff2fac704
--- /dev/null
+++ b/testsuites/libtests/ttest02/ttest02.scn
@@ -0,0 +1,37 @@
+*** BEGIN OF TEST TTEST 2 ***
+*** TEST VERSION: 6.0.0.133fcd71c16b87b5c3924c04039a125be9affcfa
+*** TEST STATE: EXPECTED_PASS
+*** TEST BUILD: RTEMS_SMP
+*** TEST TOOLS: 10.0.1 20200406 (RTEMS 6, RSB b69f54d51740810dc54a50662f5da4d4ba0ddd18, Newlib ece49e4)
+A:TTEST 2
+S:Platform:RTEMS
+S:Compiler:10.0.1 20200406 (RTEMS 6, RSB b69f54d51740810dc54a50662f5da4d4ba0ddd18, Newlib ece49e4)
+S:Version:6.0.0.133fcd71c16b87b5c3924c04039a125be9affcfa
+S:BSP:leon3
+S:RTEMS_DEBUG:0
+S:RTEMS_MULTIPROCESSING:0
+S:RTEMS_POSIX_API:0
+S:RTEMS_PROFILING:0
+S:RTEMS_SMP:1
+B:TestInterruptTimeout
+P:0:0:UI1:init.c:130
+E:TestInterruptTimeout:N:1:F:0:D:0.042180
+B:TestInterruptFatal
+P:0:0:UI1:init.c:137
+E:TestInterruptFatal:N:1:F:0:D:0.000360
+B:TestInterruptDone
+P:0:0:UI1:init.c:114
+P:1:0:UI1:init.c:114
+P:2:0:UI1:init.c:114
+P:3:0:UI1:init.c:114
+P:4:0:UI1:init.c:114
+P:5:0:UI1:init.c:114
+P:6:0:UI1:init.c:114
+P:7:0:UI1:init.c:114
+P:8:0:UI1:init.c:114
+P:9:0:UI1:init.c:114
+E:TestInterruptDone:N:10:F:0:D:1.233900
+Z:TTEST 2:C:3:N:12:F:0:D:1.277400
+Y:ReportHash:SHA256:308c997b3220d239738a11dac4133d9f987a34b3f5f9baf1158d1a54f85cc647
+
+*** END OF TEST TTEST 2 ***
--
2.26.2
More information about the devel
mailing list