summaryrefslogtreecommitdiffstats
path: root/testsuites/validation/tc-score-thread.c
diff options
context:
space:
mode:
Diffstat (limited to 'testsuites/validation/tc-score-thread.c')
-rw-r--r--testsuites/validation/tc-score-thread.c223
1 files changed, 219 insertions, 4 deletions
diff --git a/testsuites/validation/tc-score-thread.c b/testsuites/validation/tc-score-thread.c
index 53b939e3c5..e065905641 100644
--- a/testsuites/validation/tc-score-thread.c
+++ b/testsuites/validation/tc-score-thread.c
@@ -3,11 +3,11 @@
/**
* @file
*
- * @ingroup RTEMSTestCaseScoreThreadValThread
+ * @ingroup ScoreThreadValThread
*/
/*
- * Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de)
+ * Copyright (C) 2021, 2023 embedded brains GmbH & Co. KG
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -56,14 +56,15 @@
#include <rtems/score/statesimpl.h>
#include <rtems/score/threadimpl.h>
+#include "ts-config.h"
#include "tx-support.h"
#include <rtems/test.h>
/**
- * @defgroup RTEMSTestCaseScoreThreadValThread spec:/score/thread/val/thread
+ * @defgroup ScoreThreadValThread spec:/score/thread/val/thread
*
- * @ingroup RTEMSTestSuiteTestsuitesValidationNoClock0
+ * @ingroup TestsuitesValidationNoClock0
*
* @brief Tests general thread behaviour.
*
@@ -86,6 +87,30 @@
*
* - Clean up all used resources.
*
+ * - Delete a thread which least recently used the floating point coprocessor.
+ *
+ * - Start the worker thread. Let it use the floating point coprocessor.
+ *
+ * - Delete the worker thread and free the thread resources.
+ *
+ * - Clean up all used resources.
+ *
+ * - Validate the global construction. Mark that the test case executed.
+ *
+ * - Check that the global constructor was called exactly once.
+ *
+ * - Check that the global construction was done by the Classic API user
+ * initialization task.
+ *
+ * - Check that the global constructor was called before the task entry.
+ *
+ * - Validate that thread dispatching does not recurse. Issue a couple of
+ * thread context switches during a thread dispatch. Record the stack
+ * pointers of the heir threads.
+ *
+ * - Check that the thread dispatching did not recurse through the recorded
+ * stack pointers.
+ *
* @{
*/
@@ -102,6 +127,26 @@ typedef struct {
* @brief This member contains the killer task identifier.
*/
rtems_id killer_id;
+
+ /**
+ * @brief This member contains a floating-point object.
+ */
+ volatile double fp_obj;
+
+ /**
+ * @brief This member indicates the thread switch state.
+ */
+ int thread_switch_state;
+
+ /**
+ * @brief This member contain the runner stack pointer at the context switch.
+ */
+ uintptr_t runner_stack[ 2 ];
+
+ /**
+ * @brief This member contain the worker stack pointer at the context switch.
+ */
+ uintptr_t worker_stack[ 2 ];
} ScoreThreadValThread_Context;
static ScoreThreadValThread_Context
@@ -109,6 +154,21 @@ static ScoreThreadValThread_Context
typedef ScoreThreadValThread_Context Context;
+static bool test_case_executed;
+
+static bool constructor_test_case_executed;
+
+static uint32_t constructor_calls;
+
+static rtems_id constructor_id;
+
+static __attribute__(( __constructor__ )) void Constructor( void )
+{
+ constructor_test_case_executed = test_case_executed;
+ ++constructor_calls;
+ constructor_id = rtems_task_self();
+}
+
static void TaskTerminate( rtems_tcb *executing )
{
Context *ctx;
@@ -126,6 +186,29 @@ static void WorkerTask( rtems_task_argument arg )
SuspendSelf();
}
+static void GoBackToRunner( void *arg )
+{
+ Context *ctx;
+
+ ctx = arg;
+ SetPriority( ctx->worker_id, PRIO_LOW );
+}
+
+static void FloatingPointTask( rtems_task_argument arg )
+{
+ Context *ctx;
+
+ ctx = (Context *) arg;
+ ctx->fp_obj *= 1.23;
+
+ /*
+ * We use an interrupt to go back to the runner since on some
+ * architectures, the floating-point context is only saved during interrupt
+ * processing and not for synchronous thread switches.
+ */
+ CallWithinISR( GoBackToRunner, ctx );
+}
+
static void KillerTask( rtems_task_argument arg )
{
Context *ctx;
@@ -134,6 +217,44 @@ static void KillerTask( rtems_task_argument arg )
DeleteTask( ctx->worker_id );
}
+static void TaskSwitch( rtems_tcb *executing, rtems_tcb *heir )
+{
+ Context *ctx;
+ rtems_id worker_id;
+ int state;
+ uintptr_t heir_stack;
+
+ ctx = T_fixture_context();
+ worker_id = ctx->worker_id;
+ state = ctx->thread_switch_state;
+ ctx->thread_switch_state = state + 1;
+ heir_stack = _CPU_Context_Get_SP( &heir->Registers );
+
+ switch ( state ) {
+ case 0:
+ T_eq_u32( heir->Object.id, worker_id );
+ SuspendTask( worker_id );
+ ctx->worker_stack[ 0 ] = heir_stack;
+ break;
+ case 1:
+ T_eq_u32( executing->Object.id, worker_id );
+ ResumeTask( worker_id );
+ ctx->runner_stack[ 0 ] = heir_stack;
+ break;
+ case 2:
+ T_eq_u32( heir->Object.id, worker_id );
+ SuspendTask( worker_id );
+ ctx->worker_stack[ 1 ] = heir_stack;
+ break;
+ case 3:
+ T_eq_u32( executing->Object.id, worker_id );
+ ctx->runner_stack[ 1 ] = heir_stack;
+ break;
+ default:
+ T_unreachable();
+ }
+}
+
static T_fixture ScoreThreadValThread_Fixture = {
.setup = NULL,
.stop = NULL,
@@ -217,6 +338,97 @@ static void ScoreThreadValThread_Action_0( ScoreThreadValThread_Context *ctx )
}
/**
+ * @brief Delete a thread which least recently used the floating point
+ * coprocessor.
+ */
+static void ScoreThreadValThread_Action_1( ScoreThreadValThread_Context *ctx )
+{
+ rtems_status_code sc;
+
+ SetSelfPriority( PRIO_NORMAL );
+ sc = rtems_task_create(
+ rtems_build_name( 'W', 'O', 'R', 'K'),
+ PRIO_HIGH,
+ TEST_MINIMUM_STACK_SIZE,
+ RTEMS_DEFAULT_MODES,
+ RTEMS_FLOATING_POINT,
+ &ctx->worker_id
+ );
+ T_rsc_success( sc );
+
+ /*
+ * Start the worker thread. Let it use the floating point coprocessor.
+ */
+ StartTask( ctx->worker_id, FloatingPointTask, ctx );
+
+ /*
+ * Delete the worker thread and free the thread resources.
+ */
+ DeleteTask( ctx->worker_id );
+ KillZombies();
+
+ /*
+ * Clean up all used resources.
+ */
+ RestoreRunnerPriority();
+}
+
+/**
+ * @brief Validate the global construction. Mark that the test case executed.
+ */
+static void ScoreThreadValThread_Action_2( ScoreThreadValThread_Context *ctx )
+{
+ test_case_executed = true;
+
+ /*
+ * Check that the global constructor was called exactly once.
+ */
+ T_eq_u32( constructor_calls, 1 );
+
+ /*
+ * Check that the global construction was done by the Classic API user
+ * initialization task.
+ */
+ T_eq_u32( constructor_id, rtems_task_self() );
+
+ /*
+ * Check that the global constructor was called before the task entry.
+ */
+ T_false( constructor_test_case_executed );
+}
+
+/**
+ * @brief Validate that thread dispatching does not recurse. Issue a couple of
+ * thread context switches during a thread dispatch. Record the stack
+ * pointers of the heir threads.
+ */
+static void ScoreThreadValThread_Action_3( ScoreThreadValThread_Context *ctx )
+{
+ SetSelfPriority( PRIO_NORMAL );
+ ctx->worker_id = CreateTask( "WORK", PRIO_HIGH );
+ StartTask( ctx->worker_id, WorkerTask, NULL );
+
+ ctx->thread_switch_state = 0;
+ ctx->runner_stack[ 0 ] = 0;
+ ctx->runner_stack[ 1 ] = 1;
+ ctx->worker_stack[ 0 ] = 0;
+ ctx->worker_stack[ 1 ] = 1;
+ SetTaskSwitchExtension( TaskSwitch );
+ ResumeTask( ctx->worker_id );
+
+ SetTaskSwitchExtension( NULL );
+ DeleteTask( ctx->worker_id );
+ RestoreRunnerPriority();
+
+ /*
+ * Check that the thread dispatching did not recurse through the recorded
+ * stack pointers.
+ */
+ T_eq_uptr( ctx->runner_stack[ 0 ], ctx->runner_stack[ 1 ] );
+ T_eq_uptr( ctx->worker_stack[ 0 ], ctx->worker_stack[ 1 ] );
+}
+
+/**
* @fn void T_case_body_ScoreThreadValThread( void )
*/
T_TEST_CASE_FIXTURE( ScoreThreadValThread, &ScoreThreadValThread_Fixture )
@@ -226,6 +438,9 @@ T_TEST_CASE_FIXTURE( ScoreThreadValThread, &ScoreThreadValThread_Fixture )
ctx = T_fixture_context();
ScoreThreadValThread_Action_0( ctx );
+ ScoreThreadValThread_Action_1( ctx );
+ ScoreThreadValThread_Action_2( ctx );
+ ScoreThreadValThread_Action_3( ctx );
}
/** @} */