[rtems commit] libtest: Add T_interrupt_test()

Sebastian Huber sebh at rtems.org
Thu Jul 23 08:57:41 UTC 2020


Module:    rtems
Branch:    master
Commit:    cc3fd8fcf182cfa35388fc79c14e784a968570ae
Changeset: http://git.rtems.org/rtems/commit/?id=cc3fd8fcf182cfa35388fc79c14e784a968570ae

Author:    Sebastian Huber <sebastian.huber at embedded-brains.de>
Date:      Fri Jul 17 19:42:32 2020 +0200

libtest: Add T_interrupt_test()

Update #3199.

---

 cpukit/Makefile.am                      |   1 +
 cpukit/include/rtems/test.h             |  30 +++
 cpukit/libtest/t-test-interrupt.c       | 441 ++++++++++++++++++++++++++++++++
 testsuites/libtests/Makefile.am         |   9 +
 testsuites/libtests/configure.ac        |   1 +
 testsuites/libtests/ttest02/init.c      | 174 +++++++++++++
 testsuites/libtests/ttest02/ttest02.doc |  11 +
 testsuites/libtests/ttest02/ttest02.scn |  37 +++
 8 files changed, 704 insertions(+)

diff --git a/cpukit/Makefile.am b/cpukit/Makefile.am
index 89edaef..75e119e 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 5d4c676..a7955c7 100644
--- a/cpukit/include/rtems/test.h
+++ b/cpukit/include/rtems/test.h
@@ -2360,6 +2360,36 @@ 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);
+
+void T_interrupt_test_busy_wait_for_interrupt(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 0000000..7012319
--- /dev/null
+++ b/cpukit/libtest/t-test-interrupt.c
@@ -0,0 +1,441 @@
+/* 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);
+}
+
+void
+T_interrupt_test_busy_wait_for_interrupt(void)
+{
+	T_interrupt_context *ctx;
+	unsigned int state;
+
+	ctx = &T_interrupt_instance;
+
+	do {
+		state = _Atomic_Load_uint(&ctx->state, ATOMIC_ORDER_RELAXED);
+	} while (state == T_INTERRUPT_TEST_ACTION);
+}
+
+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;
+
+			/* Round down to make sure no underflow happens */
+			lower = lower_bound[sample];
+			delta = lower / 32;
+			lower_sum -= delta;
+			lower_bound[sample] = lower - delta;
+
+			sample = (sample + 1) % T_INTERRUPT_SAMPLE_COUNT;
+		} else if (state == T_INTERRUPT_TEST_LATE) {
+			uint_fast32_t upper;
+
+			lower_sum -= lower_bound[sample];
+			lower_sum += busy;
+			lower_bound[sample] = busy;
+
+			/*
+			 * The one tick busy count value is not really
+			 * trustable on some platforms.  Allow the upper bound
+			 * to grow over this value in time.
+			 */
+			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 c312f14..2ff05f2 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 3b54626..2fbcb61 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 0000000..0f907e1
--- /dev/null
+++ b/testsuites/libtests/ttest02/init.c
@@ -0,0 +1,174 @@
+/* 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/test-info.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);
+
+	T_interrupt_test_busy_wait_for_interrupt();
+}
+
+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 0000000..193f288
--- /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 0000000..7ff2fac
--- /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 ***



More information about the vc mailing list