forked from Imagelibrary/rtems
@@ -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
|
||||
|
||||
@@ -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 *);
|
||||
|
||||
441
cpukit/libtest/t-test-interrupt.c
Normal file
441
cpukit/libtest/t-test-interrupt.c
Normal file
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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])
|
||||
|
||||
174
testsuites/libtests/ttest02/init.c
Normal file
174
testsuites/libtests/ttest02/init.c
Normal file
@@ -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>
|
||||
11
testsuites/libtests/ttest02/ttest02.doc
Normal file
11
testsuites/libtests/ttest02/ttest02.doc
Normal file
@@ -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.
|
||||
37
testsuites/libtests/ttest02/ttest02.scn
Normal file
37
testsuites/libtests/ttest02/ttest02.scn
Normal file
@@ -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 ***
|
||||
Reference in New Issue
Block a user