summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2021-08-08 16:12:39 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2021-09-15 07:50:49 +0200
commit17ba4c60c7b34c7646b2d17cc0f21a52391ddfa4 (patch)
tree98581f1ac440829bc489a80ac7a01da1923af5c4
parenta5d97fbb1a8dba4ed47a1d9639423e1dbe3f3489 (diff)
validation: Test user extensions
-rw-r--r--spec/build/testsuites/validation/grp.yml2
-rw-r--r--spec/build/testsuites/validation/userext.yml21
-rw-r--r--testsuites/validation/tc-terminate.c154
-rw-r--r--testsuites/validation/tc-userext.c849
-rw-r--r--testsuites/validation/tc-userext.h (renamed from testsuites/validation/tc-terminate.h)38
-rw-r--r--testsuites/validation/ts-default.h2
-rw-r--r--testsuites/validation/ts-terminate.c4
-rw-r--r--testsuites/validation/ts-userext.c97
8 files changed, 1113 insertions, 54 deletions
diff --git a/spec/build/testsuites/validation/grp.yml b/spec/build/testsuites/validation/grp.yml
index 3f3b93922f..746894b891 100644
--- a/spec/build/testsuites/validation/grp.yml
+++ b/spec/build/testsuites/validation/grp.yml
@@ -43,6 +43,8 @@ links:
- role: build-dependency
uid: terminate
- role: build-dependency
+ uid: userext
+- role: build-dependency
uid: validation-0
- role: build-dependency
uid: validation-1
diff --git a/spec/build/testsuites/validation/userext.yml b/spec/build/testsuites/validation/userext.yml
new file mode 100644
index 0000000000..665f2e9622
--- /dev/null
+++ b/spec/build/testsuites/validation/userext.yml
@@ -0,0 +1,21 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+build-type: test-program
+cflags: []
+copyrights:
+- Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de)
+cppflags: []
+cxxflags: []
+enabled-by: true
+features: c cprogram
+includes: []
+ldflags: []
+links: []
+source:
+- testsuites/validation/tc-userext.c
+- testsuites/validation/ts-userext.c
+stlib: []
+target: testsuites/validation/ts-userext.exe
+type: build
+use-after:
+- validation
+use-before: []
diff --git a/testsuites/validation/tc-terminate.c b/testsuites/validation/tc-terminate.c
index 3d31f4720b..ae21d205cd 100644
--- a/testsuites/validation/tc-terminate.c
+++ b/testsuites/validation/tc-terminate.c
@@ -61,7 +61,7 @@
#include <rtems/score/percpu.h>
#include <rtems/score/sysstate.h>
-#include "tc-terminate.h"
+#include "tc-userext.h"
#include <rtems/test.h>
@@ -75,8 +75,8 @@
*
* This test case performs the following actions:
*
- * - Create three dynamic extensions. Call the system termination procedure.
- * Delete one dynamic extension during the fatal extension invocation.
+ * - Create five dynamic extensions. Call the system termination procedure.
+ * Delete three dynamic extension during the fatal extension invocation.
* Delete the two remaining dynamic extensions.
*
* - Check that the fatal extensions were invoked with the expected source.
@@ -114,7 +114,7 @@ typedef struct {
static Atomic_Uint counter;
-static FatalInfo info[ 5 ];
+static FatalInfo info[ 7 ];
static bool test_case_active;
@@ -128,7 +128,7 @@ static rtems_fatal_source halt_source;
static rtems_fatal_code halt_code;
-static rtems_id extension_id_4;
+static rtems_id extension_ids[ 7 ];
static unsigned int GetCounter( void )
{
@@ -195,7 +195,12 @@ static void FatalExtension2(
rtems_fatal_code code
)
{
+ rtems_status_code sc;
+
FatalExtension( source, always_set_to_false, code, 2 );
+
+ sc = rtems_extension_delete( extension_ids[ 3 ] );
+ T_quiet_rsc_success( sc );
}
static void FatalExtension3(
@@ -204,34 +209,55 @@ static void FatalExtension3(
rtems_fatal_code code
)
{
+ FatalExtension( source, always_set_to_false, code, 3 );
+}
+
+static void FatalExtension4(
+ rtems_fatal_source source,
+ bool always_set_to_false,
+ rtems_fatal_code code
+)
+{
+ FatalExtension( source, always_set_to_false, code, 4 );
+}
+
+static void FatalExtension5(
+ rtems_fatal_source source,
+ bool always_set_to_false,
+ rtems_fatal_code code
+)
+{
rtems_status_code sc;
- FatalExtension( source, always_set_to_false, code, 3 );
+ FatalExtension( source, always_set_to_false, code, 5 );
- sc = rtems_extension_delete( extension_id_4 );
+ sc = rtems_extension_delete( extension_ids[ 5 ] );
T_quiet_rsc_success( sc );
}
-static void FatalExtension4(
+static void FatalExtension6(
rtems_fatal_source source,
bool always_set_to_false,
rtems_fatal_code code
)
{
- FatalExtension( source, always_set_to_false, code, 3 );
+ rtems_status_code sc;
+
+ FatalExtension( source, always_set_to_false, code, 6 );
+
+ sc = rtems_extension_delete( extension_ids[ 4 ] );
+ T_quiet_rsc_success( sc );
}
/**
- * @brief Create three dynamic extensions. Call the system termination
- * procedure. Delete one dynamic extension during the fatal extension
- * invocation. Delete the two remaining dynamic extensions.
+ * @brief Create five dynamic extensions. Call the system termination
+ * procedure. Delete three dynamic extension during the fatal extension
+ * invocation. Delete the two remaining dynamic extensions.
*/
static void ScoreInterrValTerminate_Action_0( void )
{
rtems_status_code sc;
rtems_extensions_table table;
- rtems_id id_2;
- rtems_id id_3;
bool shutdown_ok;
#if defined(RTEMS_SMP)
@@ -246,7 +272,7 @@ static void ScoreInterrValTerminate_Action_0( void )
sc = rtems_extension_create(
rtems_build_name( ' ', ' ', ' ', '2' ),
&table,
- &id_2
+ &extension_ids[ 2 ]
);
T_step_rsc_success( 0, sc );
@@ -254,7 +280,7 @@ static void ScoreInterrValTerminate_Action_0( void )
sc = rtems_extension_create(
rtems_build_name( ' ', ' ', ' ', '3' ),
&table,
- &id_3
+ &extension_ids[ 3 ]
);
T_step_rsc_success( 1, sc );
@@ -262,10 +288,26 @@ static void ScoreInterrValTerminate_Action_0( void )
sc = rtems_extension_create(
rtems_build_name( ' ', ' ', ' ', '4' ),
&table,
- &extension_id_4
+ &extension_ids[ 4 ]
);
T_step_rsc_success( 2, sc );
+ table.fatal = FatalExtension5;
+ sc = rtems_extension_create(
+ rtems_build_name( ' ', ' ', ' ', '5' ),
+ &table,
+ &extension_ids[ 5 ]
+ );
+ T_step_rsc_success( 3, sc );
+
+ table.fatal = FatalExtension6;
+ sc = rtems_extension_create(
+ rtems_build_name( ' ', ' ', ' ', '6' ),
+ &table,
+ &extension_ids[ 6 ]
+ );
+ T_step_rsc_success( 4, sc );
+
test_case_active = true;
if ( setjmp( before_terminate ) == 0 ) {
@@ -274,33 +316,43 @@ static void ScoreInterrValTerminate_Action_0( void )
test_case_active = false;
- sc = rtems_extension_delete( id_2 );
- T_step_rsc_success( 3, sc );
+ sc = rtems_extension_delete( extension_ids[ 2 ] );
+ T_step_rsc_success( 5, sc );
- sc = rtems_extension_delete( id_3 );
- T_step_rsc_success( 4, sc );
+ sc = rtems_extension_delete( extension_ids[ 6 ] );
+ T_step_rsc_success( 6, sc );
/*
* Check that the fatal extensions were invoked with the expected source.
*/
T_step_eq_int(
- 5,
+ 7,
info[ 0 ].source,
RTEMS_FATAL_SOURCE_APPLICATION
);
T_step_eq_int(
- 6,
+ 8,
info[ 1 ].source,
RTEMS_FATAL_SOURCE_APPLICATION
);
T_step_eq_int(
- 7,
+ 9,
info[ 2 ].source,
RTEMS_FATAL_SOURCE_APPLICATION
);
T_step_eq_int(
- 8,
- info[ 3 ].source,
+ 10,
+ info[ 4 ].source,
+ RTEMS_FATAL_SOURCE_APPLICATION
+ );
+ T_step_eq_int(
+ 11,
+ info[ 5 ].source,
+ RTEMS_FATAL_SOURCE_APPLICATION
+ );
+ T_step_eq_int(
+ 12,
+ info[ 6 ].source,
RTEMS_FATAL_SOURCE_APPLICATION
);
@@ -308,40 +360,46 @@ static void ScoreInterrValTerminate_Action_0( void )
* Check that the fatal extensions were invoked with the expected always set
* to false argument.
*/
- T_step_false( 9, info[ 0 ].always_set_to_false );
- T_step_false( 10, info[ 1 ].always_set_to_false );
- T_step_false( 11, info[ 2 ].always_set_to_false );
- T_step_false( 12, info[ 3 ].always_set_to_false );
+ T_step_false( 13, info[ 0 ].always_set_to_false );
+ T_step_false( 14, info[ 1 ].always_set_to_false );
+ T_step_false( 15, info[ 2 ].always_set_to_false );
+ T_step_false( 16, info[ 4 ].always_set_to_false );
+ T_step_false( 17, info[ 5 ].always_set_to_false );
+ T_step_false( 18, info[ 6 ].always_set_to_false );
/*
* Check that the fatal extensions were invoked with the expected code.
*/
- T_step_eq_ulong( 13, info[ 0 ].code, 123456 );
- T_step_eq_ulong( 14, info[ 1 ].code, 123456 );
- T_step_eq_ulong( 15, info[ 2 ].code, 123456 );
- T_step_eq_ulong( 16, info[ 3 ].code, 123456 );
+ T_step_eq_ulong( 19, info[ 0 ].code, 123456 );
+ T_step_eq_ulong( 20, info[ 1 ].code, 123456 );
+ T_step_eq_ulong( 21, info[ 2 ].code, 123456 );
+ T_step_eq_ulong( 22, info[ 4 ].code, 123456 );
+ T_step_eq_ulong( 23, info[ 5 ].code, 123456 );
+ T_step_eq_ulong( 24, info[ 6 ].code, 123456 );
/*
* Check that the fatal extensions were invoked in forward order.
*/
- T_step_eq_uint( 17, info[ 0 ].counter, 1 );
- T_step_eq_uint( 18, info[ 1 ].counter, 2 );
- T_step_eq_uint( 19, info[ 2 ].counter, 3 );
- T_step_eq_uint( 20, info[ 3 ].counter, 4 );
+ T_step_eq_uint( 25, info[ 0 ].counter, 1 );
+ T_step_eq_uint( 26, info[ 1 ].counter, 2 );
+ T_step_eq_uint( 27, info[ 2 ].counter, 3 );
+ T_step_eq_uint( 28, info[ 4 ].counter, 4 );
+ T_step_eq_uint( 29, info[ 5 ].counter, 5 );
+ T_step_eq_uint( 30, info[ 6 ].counter, 6 );
/*
* Check that the fatal extension in the deleted extension set was not
* invoked.
*/
- T_step_eq_int( 21, info[ 4 ].source, 0 );
- T_step_false( 22, info[ 4 ].always_set_to_false );
- T_step_eq_ulong( 23, info[ 4 ].code, 0 );
- T_step_eq_uint( 24, info[ 4 ].counter, 0 );
+ T_step_eq_int( 31, info[ 3 ].source, 0 );
+ T_step_false( 32, info[ 3 ].always_set_to_false );
+ T_step_eq_ulong( 33, info[ 3 ].code, 0 );
+ T_step_eq_uint( 34, info[ 3 ].counter, 0 );
/*
* Check that the system state is terminated.
*/
- T_step_eq_int( 25, _System_state_Get(), SYSTEM_STATE_TERMINATED );
+ T_step_eq_int( 35, _System_state_Get(), SYSTEM_STATE_TERMINATED );
/*
* Where the system was built with SMP support enabled, check that a shutdown
@@ -352,22 +410,22 @@ static void ScoreInterrValTerminate_Action_0( void )
_Per_CPU_Get_state( _Per_CPU_Get() ) == PER_CPU_STATE_SHUTDOWN );
_ISR_Set_level( 0 );
#endif
- T_step_true( 26, shutdown_ok );
+ T_step_true( 36, shutdown_ok );
/*
* Check that the system was halted with the expected fatal source.
*/
- T_step_eq_int( 27, halt_source, RTEMS_FATAL_SOURCE_APPLICATION );
+ T_step_eq_int( 37, halt_source, RTEMS_FATAL_SOURCE_APPLICATION );
/*
* Check that the system was halted with the expected fatal code.
*/
- T_step_eq_ulong( 28, halt_code, 123456 );
+ T_step_eq_ulong( 38, halt_code, 123456 );
/*
* Check that the system was finally halted.
*/
- T_step_eq_uint( 29, counter, 5 );
+ T_step_eq_uint( 39, counter, 7 );
}
/**
@@ -375,7 +433,7 @@ static void ScoreInterrValTerminate_Action_0( void )
*/
T_TEST_CASE( ScoreInterrValTerminate )
{
- T_plan( 30 );
+ T_plan( 40 );
ScoreInterrValTerminate_Action_0();
}
diff --git a/testsuites/validation/tc-userext.c b/testsuites/validation/tc-userext.c
new file mode 100644
index 0000000000..2d4420cab5
--- /dev/null
+++ b/testsuites/validation/tc-userext.c
@@ -0,0 +1,849 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/**
+ * @file
+ *
+ * @ingroup RTEMSTestCaseRtemsUserextValUserext
+ */
+
+/*
+ * Copyright (C) 2021 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.
+ */
+
+/*
+ * This file is part of the RTEMS quality process and was automatically
+ * generated. If you find something that needs to be fixed or
+ * worded better please post a report or patch to an RTEMS mailing list
+ * or raise a bug report:
+ *
+ * https://www.rtems.org/bugs.html
+ *
+ * For information on updating and regenerating please refer to the How-To
+ * section in the Software Requirements Engineering chapter of the
+ * RTEMS Software Engineering manual. The manual is provided as a part of
+ * a release. For development sources please refer to the online
+ * documentation at:
+ *
+ * https://docs.rtems.org
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <rtems/score/apimutex.h>
+#include <rtems/score/atomic.h>
+
+#include "tc-userext.h"
+#include "tx-support.h"
+
+#include <rtems/test.h>
+
+/**
+ * @defgroup RTEMSTestCaseRtemsUserextValUserext \
+ * spec:/rtems/userext/val/userext
+ *
+ * @ingroup RTEMSTestSuiteTestsuitesUserext
+ *
+ * @brief Tests the thread user extensions.
+ *
+ * This test case performs the following actions:
+ *
+ * - Create five dynamic extensions. Switch to a started thread. Delete three
+ * dynamic extension during the thread begin invocation. Clean up the used
+ * resources.
+ *
+ * - Check that the thread switch extensions were invoked in the right order
+ * before the thread begin extensions.
+ *
+ * - Check that the thread begin extensions were invoked in the right order.
+ *
+ * - Check that the other extensions were not invoked.
+ *
+ * - Check that the thread begin extension of the extension set deleted
+ * before its turn in the invocation was not invoked.
+ *
+ * - Create five dynamic extensions. Create a thread. Delete three dynamic
+ * extension during the thread create invocation. Clean up the used
+ * resources.
+ *
+ * - Check that the thread create extensions were invoked in the right order.
+ *
+ * - Check that the thread create extensions were invoked under protection of
+ * the allocator mutex.
+ *
+ * - Check that the other extensions were not invoked.
+ *
+ * - Check that the thread create extension of the extension set deleted
+ * before its turn in the invocation was not invoked.
+ *
+ * - Create five dynamic extensions. Delete a thread. Delete three dynamic
+ * extension during the thread delete invocation. Clean up the used
+ * resources.
+ *
+ * - Check that the thread delete extensions were invoked in the right order.
+ *
+ * - Check that the thread delete extensions were invoked under protection of
+ * the allocator mutex.
+ *
+ * - Check that the other extensions were not invoked.
+ *
+ * - Check that the thread delete extension of the extension set deleted
+ * before its turn in the invocation was not invoked.
+ *
+ * - Create five dynamic extensions. Return from a thread entry. Delete three
+ * dynamic extension during the thread exitted invocation. Clean up the used
+ * resources.
+ *
+ * - Check that the thread exitted extensions were invoked in the right
+ * order.
+ *
+ * - Check that the other extensions were not invoked.
+ *
+ * - Check that the thread exitted extension of the extension set deleted
+ * before its turn in the invocation was not invoked.
+ *
+ * - Create five dynamic extensions. Restart a thread. Delete three dynamic
+ * extension during the thread restart invocation. Clean up the used
+ * resources.
+ *
+ * - Check that the thread restart extensions were invoked in the right
+ * order.
+ *
+ * - Check that the other extensions were not invoked.
+ *
+ * - Check that the thread restart extension of the extension set deleted
+ * before its turn in the invocation was not invoked.
+ *
+ * - Create five dynamic extensions. Start a thread. Delete three dynamic
+ * extension during the thread start invocation. Clean up the used
+ * resources.
+ *
+ * - Check that the thread start extensions were invoked in the right order.
+ *
+ * - Check that the other extensions were not invoked.
+ *
+ * - Check that the thread start extension of the extension set deleted
+ * before its turn in the invocation was not invoked.
+ *
+ * - Create five dynamic extensions. Terminate a thread. Delete three dynamic
+ * extension during the thread terminate invocation. Clean up the used
+ * resources.
+ *
+ * - Check that the thread terminate extensions were invoked in the right
+ * order.
+ *
+ * - Check that the other extensions were not invoked.
+ *
+ * - Check that the thread terminate extension of the extension set deleted
+ * before its turn in the invocation was not invoked.
+ *
+ * @{
+ */
+
+static void RtemsUserextValUserext_Setup( void *ctx )
+{
+ SetSelfPriority( PRIO_NORMAL );
+}
+
+static void RtemsUserextValUserext_Teardown( void *ctx )
+{
+ RestoreRunnerPriority();
+}
+
+static T_fixture RtemsUserextValUserext_Fixture = {
+ .setup = RtemsUserextValUserext_Setup,
+ .stop = NULL,
+ .teardown = RtemsUserextValUserext_Teardown,
+ .scope = NULL,
+ .initial_context = NULL
+};
+
+typedef struct {
+ unsigned int counter;
+ rtems_tcb *executing;
+ rtems_tcb *thread;
+} ExtensionEvent;
+
+typedef enum {
+ THREAD_BEGIN,
+ THREAD_CREATE,
+ THREAD_DELETE,
+ THREAD_EXITTED,
+ THREAD_RESTART,
+ THREAD_START,
+ THREAD_SWITCH,
+ THREAD_TERMINATE,
+ EXTENSION_KIND_COUNT
+} ExtensionKind;
+
+static rtems_id extension_ids[ 7 ];
+
+static Atomic_Uint extension_counter[ RTEMS_ARRAY_SIZE( extension_ids ) ]
+ [ EXTENSION_KIND_COUNT ];
+
+static ExtensionEvent extension_events[ RTEMS_ARRAY_SIZE( extension_ids ) ]
+ [ EXTENSION_KIND_COUNT ][ 3 ];
+
+static Atomic_Uint global_counter;
+
+static ExtensionKind extension_under_test = EXTENSION_KIND_COUNT;
+
+static uint32_t thread_create_allocator_owner_count;
+
+static uint32_t thread_delete_allocator_owner_count;
+
+static void StopTestCase( void )
+{
+ ExtensionKind kind;
+ rtems_status_code sc;
+
+ kind = extension_under_test;
+ extension_under_test = EXTENSION_KIND_COUNT;
+
+ sc = rtems_extension_delete( extension_ids[ 2 ] );
+ T_rsc_success( sc );
+
+ if ( kind == THREAD_SWITCH ) {
+ sc = rtems_extension_delete( extension_ids[ 3 ] );
+ T_rsc_success( sc );
+
+ sc = rtems_extension_delete( extension_ids[ 4 ] );
+ T_rsc_success( sc );
+
+ sc = rtems_extension_delete( extension_ids[ 5 ] );
+ T_rsc_success( sc );
+ }
+
+ sc = rtems_extension_delete( extension_ids[ 6 ] );
+ T_rsc_success( sc );
+}
+
+static void Extension(
+ size_t index,
+ ExtensionKind kind,
+ rtems_tcb *executing,
+ rtems_tcb *thread
+)
+{
+ unsigned int gc;
+ unsigned int c;
+ rtems_status_code sc;
+
+ if ( extension_under_test == EXTENSION_KIND_COUNT ) {
+ return;
+ }
+
+ if ( kind == THREAD_CREATE && _RTEMS_Allocator_is_owner() ) {
+ ++thread_create_allocator_owner_count;
+ }
+
+ if ( kind == THREAD_DELETE && _RTEMS_Allocator_is_owner() ) {
+ ++thread_delete_allocator_owner_count;
+ }
+
+ gc = _Atomic_Fetch_add_uint( &global_counter, 1, ATOMIC_ORDER_RELAXED ) + 1;
+ c = _Atomic_Fetch_add_uint(
+ &extension_counter[ index ][ kind ],
+ 1,
+ ATOMIC_ORDER_RELAXED
+ );
+
+ if ( c < RTEMS_ARRAY_SIZE( extension_events[ index ][ kind ] ) ) {
+ extension_events[ index ][ kind ][ c ].counter = gc;
+ extension_events[ index ][ kind ][ c ].executing = executing;
+ extension_events[ index ][ kind ][ c ].thread = thread;
+ }
+
+ if ( kind == THREAD_SWITCH ) {
+ /* Extension set deletion is not allowed in thread switch extensions */
+ return;
+ }
+
+ if ( kind != extension_under_test ) {
+ return;
+ }
+
+ if ( kind == THREAD_DELETE || kind == THREAD_TERMINATE ) {
+ if ( index == 6 ) {
+ sc = rtems_extension_delete( extension_ids[ 5 ] );
+ T_rsc_success( sc );
+ } else if ( index == 3 ) {
+ sc = rtems_extension_delete( extension_ids[ 3 ] );
+ T_rsc_success( sc );
+ } else if ( index == 2 ) {
+ sc = rtems_extension_delete( extension_ids[ 4 ] );
+ T_rsc_success( sc );
+ }
+ } else {
+ if ( index == 2 ) {
+ sc = rtems_extension_delete( extension_ids[ 3 ] );
+ T_rsc_success( sc );
+ } else if ( index == 5 ) {
+ sc = rtems_extension_delete( extension_ids[ 5 ] );
+ T_rsc_success( sc );
+ } else if ( index == 6 ) {
+ sc = rtems_extension_delete( extension_ids[ 4 ] );
+ T_rsc_success( sc );
+ }
+ }
+
+ if ( index == 6 && ( kind == THREAD_EXITTED || kind == THREAD_RESTART ) ) {
+ StopTestCase();
+ rtems_task_exit();
+ }
+
+ if ( index == 0 && kind == THREAD_TERMINATE ) {
+ StopTestCase();
+ }
+}
+
+#define DEFINE_EXTENSIONS( index, linkage ) \
+ linkage void ThreadBeginExtension##index( rtems_tcb *executing ) \
+ { \
+ Extension( index, THREAD_BEGIN, executing, NULL ); \
+ } \
+ linkage bool ThreadCreateExtension##index( \
+ rtems_tcb *executing, \
+ rtems_tcb *created \
+ ) \
+ { \
+ Extension( index, THREAD_CREATE, executing, created ); \
+ return true; \
+ } \
+ linkage void ThreadDeleteExtension##index( \
+ rtems_tcb *executing, \
+ rtems_tcb *deleted \
+ ) \
+ { \
+ Extension( index, THREAD_DELETE, executing, deleted ); \
+ } \
+ linkage void ThreadExittedExtension##index( rtems_tcb *executing ) \
+ { \
+ Extension( index, THREAD_EXITTED, executing, NULL ); \
+ } \
+ linkage void ThreadRestartExtension##index( \
+ rtems_tcb *executing, \
+ rtems_tcb *restarted \
+ ) \
+ { \
+ Extension( index, THREAD_RESTART, executing, restarted ); \
+ } \
+ linkage void ThreadStartExtension##index( \
+ rtems_tcb *executing, \
+ rtems_tcb *started \
+ ) \
+ { \
+ Extension( index, THREAD_START, executing, started ); \
+ } \
+ linkage void ThreadSwitchExtension##index( \
+ rtems_tcb *executing, \
+ rtems_tcb *heir \
+ ) \
+ { \
+ Extension( index, THREAD_SWITCH, executing, heir ); \
+ } \
+ linkage void ThreadTerminateExtension##index( rtems_tcb *executing ) \
+ { \
+ Extension( index, THREAD_TERMINATE, executing, NULL ); \
+ }
+
+DEFINE_EXTENSIONS( 0, )
+DEFINE_EXTENSIONS( 1, )
+
+#define DEFINE_EXTENSIONS_AND_TABLE( index ) \
+ DEFINE_EXTENSIONS( index, static ) \
+ static const rtems_extensions_table table_##index = { \
+ .thread_begin = ThreadBeginExtension##index, \
+ .thread_create = ThreadCreateExtension##index, \
+ .thread_delete = ThreadDeleteExtension##index, \
+ .thread_exitted = ThreadExittedExtension##index, \
+ .thread_restart = ThreadRestartExtension##index, \
+ .thread_start = ThreadStartExtension##index, \
+ .thread_switch = ThreadSwitchExtension##index, \
+ .thread_terminate = ThreadTerminateExtension##index \
+ }
+
+DEFINE_EXTENSIONS_AND_TABLE( 2 );
+DEFINE_EXTENSIONS_AND_TABLE( 3 );
+DEFINE_EXTENSIONS_AND_TABLE( 4 );
+DEFINE_EXTENSIONS_AND_TABLE( 5 );
+DEFINE_EXTENSIONS_AND_TABLE( 6 );
+
+static const rtems_extensions_table * const tables[] = {
+ NULL,
+ NULL,
+ &table_2,
+ &table_3,
+ &table_4,
+ &table_5,
+ &table_6
+};
+
+static rtems_tcb *StartTestCase( ExtensionKind kind )
+{
+ size_t i;
+
+ thread_create_allocator_owner_count = 0;
+ thread_delete_allocator_owner_count = 0;
+ _Atomic_Store_uint( &global_counter, 0, ATOMIC_ORDER_RELAXED );
+ memset( extension_counter, 0, sizeof( extension_counter ) );
+ memset( extension_events, 0, sizeof( extension_events ) );
+
+ extension_under_test = kind;
+
+ for ( i = 2; i < RTEMS_ARRAY_SIZE( extension_ids ); ++i ) {
+ rtems_status_code sc;
+
+ sc = rtems_extension_create(
+ rtems_build_name( ' ', ' ', ' ', '2' + i ),
+ tables[ i ],
+ &extension_ids[ i ]
+ );
+ T_rsc_success( sc );
+ }
+
+ return GetExecuting();
+}
+
+static void CheckForward(
+ ExtensionKind kind,
+ unsigned int counter,
+ unsigned int increment,
+ rtems_tcb *executing,
+ rtems_tcb *thread
+)
+{
+ size_t i;
+
+ for ( i = 0; i < RTEMS_ARRAY_SIZE( extension_ids ); ++i ) {
+ if ( i == 3 && kind != THREAD_SWITCH ) {
+ continue;
+ }
+
+ if ( counter == 0 ) {
+ T_eq_uint( extension_counter[ i ][ kind ], 0 );
+ } else {
+ T_eq_uint( extension_counter[ i ][ kind ], 1 );
+ T_eq_uint( extension_events[ i ][ kind ][ 0 ].counter, counter );
+ T_eq_ptr( extension_events[ i ][ kind ][ 0 ].executing, executing );
+ T_eq_ptr( extension_events[ i ][ kind ][ 0 ].thread, thread );
+
+ counter += increment;
+ }
+ }
+}
+
+static void CheckReverse(
+ ExtensionKind kind,
+ unsigned int counter,
+ unsigned int increment,
+ rtems_tcb *executing,
+ rtems_tcb *thread
+)
+{
+ size_t i;
+
+ for ( i = 0; i < RTEMS_ARRAY_SIZE( extension_ids ); ++i ) {
+ if ( i == 5 && kind != THREAD_SWITCH ) {
+ continue;
+ }
+
+ if ( counter == 0 ) {
+ T_eq_uint( extension_counter[ i ][ kind ], 0 );
+ } else {
+ T_eq_uint( extension_counter[ i ][ kind ], 1 );
+ T_eq_uint(
+ extension_events[ i ][ kind ][ 0 ].counter,
+ 7 - counter
+ );
+ T_eq_ptr( extension_events[ i ][ kind ][ 0 ].executing, executing );
+ T_eq_ptr( extension_events[ i ][ kind ][ 0 ].thread, thread );
+
+ counter += increment;
+ }
+ }
+}
+
+static void CheckDeletedNotInvoked( ExtensionKind kind )
+{
+ size_t index;
+
+ if ( kind == THREAD_DELETE || kind == THREAD_TERMINATE ) {
+ index = 5;
+ } else {
+ index = 3;
+ }
+
+ T_eq_uint( extension_events[ index ][ kind ][ 0 ].counter, 0 );
+ T_null( extension_events[ index ][ kind ][ 0 ].executing );
+ T_null( extension_events[ index ][ kind ][ 0 ].thread );
+}
+
+static void BeginWorker( rtems_task_argument arg )
+{
+ T_eq_u32( arg, 0 );
+ StopTestCase();
+ rtems_task_exit();
+}
+
+static void ExittedWorker( rtems_task_argument arg )
+{
+ T_eq_u32( arg, 0 );
+ (void) StartTestCase( THREAD_EXITTED );
+}
+
+static void RestartWorker( rtems_task_argument arg )
+{
+ T_eq_u32( arg, 0 );
+ (void) StartTestCase( THREAD_RESTART );
+ (void) rtems_task_restart( RTEMS_SELF, 1 );
+}
+
+static void StartWorker( rtems_task_argument arg )
+{
+ (void) arg;
+ T_unreachable();
+}
+
+static void TerminateWorker( rtems_task_argument arg )
+{
+ T_eq_u32( arg, 0 );
+ (void) StartTestCase( THREAD_TERMINATE );
+ rtems_task_exit();
+}
+
+/**
+ * @brief Create five dynamic extensions. Switch to a started thread. Delete
+ * three dynamic extension during the thread begin invocation. Clean up the
+ * used resources.
+ */
+static void RtemsUserextValUserext_Action_0( void )
+{
+ rtems_tcb *executing;
+ rtems_tcb *thread;
+ rtems_id id;
+
+ id = CreateTask( "WORK", PRIO_LOW );
+ thread = GetThread( id );
+ StartTask( id, BeginWorker, NULL );
+ executing = StartTestCase( THREAD_BEGIN );
+ SetPriority( id, PRIO_HIGH );
+ KillZombies();
+
+ /*
+ * Check that the thread switch extensions were invoked in the right order
+ * before the thread begin extensions.
+ */
+ CheckForward( THREAD_SWITCH, 1, 1, executing, thread );
+
+ /*
+ * Check that the thread begin extensions were invoked in the right order.
+ */
+ CheckForward( THREAD_BEGIN, 8, 1, thread, NULL );
+
+ /*
+ * Check that the other extensions were not invoked.
+ */
+ CheckForward( THREAD_CREATE, 0, 0, NULL, NULL );
+ CheckReverse( THREAD_DELETE, 0, 0, NULL, NULL );
+ CheckForward( THREAD_EXITTED, 0, 0, NULL, NULL );
+ CheckForward( THREAD_RESTART, 0, 0, NULL, NULL );
+ CheckForward( THREAD_START, 0, 0, NULL, NULL );
+ CheckReverse( THREAD_TERMINATE, 0, 0, NULL, NULL );
+
+ /*
+ * Check that the thread begin extension of the extension set deleted before
+ * its turn in the invocation was not invoked.
+ */
+ CheckDeletedNotInvoked( THREAD_BEGIN );
+}
+
+/**
+ * @brief Create five dynamic extensions. Create a thread. Delete three
+ * dynamic extension during the thread create invocation. Clean up the used
+ * resources.
+ */
+static void RtemsUserextValUserext_Action_1( void )
+{
+ rtems_tcb *executing;
+ rtems_tcb *thread;
+ rtems_id id;
+
+ executing = StartTestCase( THREAD_CREATE );
+ id = CreateTask( "WORK", PRIO_NORMAL );
+ thread = GetThread( id );
+ StopTestCase();
+ DeleteTask( id );
+ KillZombies();
+
+ /*
+ * Check that the thread create extensions were invoked in the right order.
+ */
+ CheckForward( THREAD_CREATE, 1, 1, executing, thread );
+
+ /*
+ * Check that the thread create extensions were invoked under protection of
+ * the allocator mutex.
+ */
+ T_eq_u32( thread_create_allocator_owner_count, 6 );
+
+ /*
+ * Check that the other extensions were not invoked.
+ */
+ CheckForward( THREAD_BEGIN, 0, 0, NULL, NULL );
+ CheckReverse( THREAD_DELETE, 0, 0, NULL, NULL );
+ CheckForward( THREAD_EXITTED, 0, 0, NULL, NULL );
+ CheckForward( THREAD_RESTART, 0, 0, NULL, NULL );
+ CheckForward( THREAD_START, 0, 0, NULL, NULL );
+ CheckForward( THREAD_SWITCH, 0, 0, NULL, NULL );
+ CheckReverse( THREAD_TERMINATE, 0, 0, NULL, NULL );
+
+ /*
+ * Check that the thread create extension of the extension set deleted before
+ * its turn in the invocation was not invoked.
+ */
+ CheckDeletedNotInvoked( THREAD_CREATE );
+}
+
+/**
+ * @brief Create five dynamic extensions. Delete a thread. Delete three
+ * dynamic extension during the thread delete invocation. Clean up the used
+ * resources.
+ */
+static void RtemsUserextValUserext_Action_2( void )
+{
+ rtems_tcb *executing;
+ rtems_tcb *thread;
+ rtems_id id;
+
+ id = CreateTask( "WORK", PRIO_NORMAL );
+ thread = GetThread( id );
+ DeleteTask( id );
+ executing = StartTestCase( THREAD_DELETE );
+ KillZombies();
+ StopTestCase();
+
+ /*
+ * Check that the thread delete extensions were invoked in the right order.
+ */
+ CheckReverse( THREAD_DELETE, 1, 1, executing, thread );
+
+ /*
+ * Check that the thread delete extensions were invoked under protection of
+ * the allocator mutex.
+ */
+ T_eq_u32( thread_delete_allocator_owner_count, 6 );
+
+ /*
+ * Check that the other extensions were not invoked.
+ */
+ CheckForward( THREAD_BEGIN, 0, 0, NULL, NULL );
+ CheckForward( THREAD_CREATE, 0, 0, NULL, NULL );
+ CheckForward( THREAD_EXITTED, 0, 0, NULL, NULL );
+ CheckForward( THREAD_RESTART, 0, 0, NULL, NULL );
+ CheckForward( THREAD_START, 0, 0, NULL, NULL );
+ CheckForward( THREAD_SWITCH, 0, 0, NULL, NULL );
+ CheckReverse( THREAD_TERMINATE, 0, 0, NULL, NULL );
+
+ /*
+ * Check that the thread delete extension of the extension set deleted before
+ * its turn in the invocation was not invoked.
+ */
+ CheckDeletedNotInvoked( THREAD_DELETE );
+}
+
+/**
+ * @brief Create five dynamic extensions. Return from a thread entry. Delete
+ * three dynamic extension during the thread exitted invocation. Clean up
+ * the used resources.
+ */
+static void RtemsUserextValUserext_Action_3( void )
+{
+ rtems_tcb *thread;
+ rtems_id id;
+
+ id = CreateTask( "WORK", PRIO_HIGH );
+ thread = GetThread( id );
+ StartTask( id, ExittedWorker, NULL );
+ KillZombies();
+
+ /*
+ * Check that the thread exitted extensions were invoked in the right order.
+ */
+ CheckForward( THREAD_EXITTED, 1, 1, thread, NULL );
+
+ /*
+ * Check that the other extensions were not invoked.
+ */
+ CheckForward( THREAD_BEGIN, 0, 0, NULL, NULL );
+ CheckForward( THREAD_CREATE, 0, 0, NULL, NULL );
+ CheckReverse( THREAD_DELETE, 0, 0, NULL, NULL );
+ CheckForward( THREAD_RESTART, 0, 0, NULL, NULL );
+ CheckForward( THREAD_START, 0, 0, NULL, NULL );
+ CheckForward( THREAD_SWITCH, 0, 0, NULL, NULL );
+ CheckReverse( THREAD_TERMINATE, 0, 0, NULL, NULL );
+
+ /*
+ * Check that the thread exitted extension of the extension set deleted
+ * before its turn in the invocation was not invoked.
+ */
+ CheckDeletedNotInvoked( THREAD_EXITTED );
+}
+
+/**
+ * @brief Create five dynamic extensions. Restart a thread. Delete three
+ * dynamic extension during the thread restart invocation. Clean up the used
+ * resources.
+ */
+static void RtemsUserextValUserext_Action_4( void )
+{
+ rtems_tcb *thread;
+ rtems_id id;
+
+ id = CreateTask( "WORK", PRIO_HIGH );
+ thread = GetThread( id );
+ StartTask( id, RestartWorker, NULL );
+ KillZombies();
+
+ /*
+ * Check that the thread restart extensions were invoked in the right order.
+ */
+ CheckForward( THREAD_RESTART, 1, 1, thread, thread );
+
+ /*
+ * Check that the other extensions were not invoked.
+ */
+ CheckForward( THREAD_BEGIN, 0, 0, NULL, NULL );
+ CheckForward( THREAD_EXITTED, 0, 0, NULL, NULL );
+ CheckForward( THREAD_CREATE, 0, 0, NULL, NULL );
+ CheckReverse( THREAD_DELETE, 0, 0, NULL, NULL );
+ CheckForward( THREAD_START, 0, 0, NULL, NULL );
+ CheckForward( THREAD_SWITCH, 0, 0, NULL, NULL );
+ CheckForward( THREAD_TERMINATE, 0, 0, NULL, NULL );
+
+ /*
+ * Check that the thread restart extension of the extension set deleted
+ * before its turn in the invocation was not invoked.
+ */
+ CheckDeletedNotInvoked( THREAD_RESTART );
+}
+
+/**
+ * @brief Create five dynamic extensions. Start a thread. Delete three
+ * dynamic extension during the thread start invocation. Clean up the used
+ * resources.
+ */
+static void RtemsUserextValUserext_Action_5( void )
+{
+ rtems_tcb *executing;
+ rtems_tcb *thread;
+ rtems_id id;
+
+ id = CreateTask( "WORK", PRIO_LOW );
+ thread = GetThread( id );
+ executing = StartTestCase( THREAD_START );
+ StartTask( id, StartWorker, NULL );
+ StopTestCase();
+ DeleteTask( id );
+ KillZombies();
+
+ /*
+ * Check that the thread start extensions were invoked in the right order.
+ */
+ CheckForward( THREAD_START, 1, 1, executing, thread );
+
+ /*
+ * Check that the other extensions were not invoked.
+ */
+ CheckForward( THREAD_BEGIN, 0, 0, NULL, NULL );
+ CheckForward( THREAD_EXITTED, 0, 0, NULL, NULL );
+ CheckForward( THREAD_CREATE, 0, 0, NULL, NULL );
+ CheckReverse( THREAD_DELETE, 0, 0, NULL, NULL );
+ CheckForward( THREAD_RESTART, 0, 0, NULL, NULL );
+ CheckForward( THREAD_SWITCH, 0, 0, NULL, NULL );
+ CheckForward( THREAD_TERMINATE, 0, 0, NULL, NULL );
+
+ /*
+ * Check that the thread start extension of the extension set deleted before
+ * its turn in the invocation was not invoked.
+ */
+ CheckDeletedNotInvoked( THREAD_START );
+}
+
+/**
+ * @brief Create five dynamic extensions. Terminate a thread. Delete three
+ * dynamic extension during the thread terminate invocation. Clean up the
+ * used resources.
+ */
+static void RtemsUserextValUserext_Action_6( void )
+{
+ rtems_tcb *thread;
+ rtems_id id;
+
+ id = CreateTask( "WORK", PRIO_HIGH );
+ thread = GetThread( id );
+ StartTask( id, TerminateWorker, NULL );
+ KillZombies();
+
+ /*
+ * Check that the thread terminate extensions were invoked in the right
+ * order.
+ */
+ CheckReverse( THREAD_TERMINATE, 1, 1, thread, NULL );
+
+ /*
+ * Check that the other extensions were not invoked.
+ */
+ CheckForward( THREAD_BEGIN, 0, 0, NULL, NULL );
+ CheckForward( THREAD_EXITTED, 0, 0, NULL, NULL );
+ CheckForward( THREAD_CREATE, 0, 0, NULL, NULL );
+ CheckReverse( THREAD_DELETE, 0, 0, NULL, NULL );
+ CheckForward( THREAD_RESTART, 0, 0, NULL, NULL );
+ CheckForward( THREAD_START, 0, 0, NULL, NULL );
+ CheckForward( THREAD_SWITCH, 0, 0, NULL, NULL );
+
+ /*
+ * Check that the thread terminate extension of the extension set deleted
+ * before its turn in the invocation was not invoked.
+ */
+ CheckDeletedNotInvoked( THREAD_TERMINATE );
+}
+
+/**
+ * @fn void T_case_body_RtemsUserextValUserext( void )
+ */
+T_TEST_CASE_FIXTURE( RtemsUserextValUserext, &RtemsUserextValUserext_Fixture )
+{
+ RtemsUserextValUserext_Action_0();
+ RtemsUserextValUserext_Action_1();
+ RtemsUserextValUserext_Action_2();
+ RtemsUserextValUserext_Action_3();
+ RtemsUserextValUserext_Action_4();
+ RtemsUserextValUserext_Action_5();
+ RtemsUserextValUserext_Action_6();
+}
+
+/** @} */
diff --git a/testsuites/validation/tc-terminate.h b/testsuites/validation/tc-userext.h
index e46c8b0b16..dbe9e30b67 100644
--- a/testsuites/validation/tc-terminate.h
+++ b/testsuites/validation/tc-userext.h
@@ -33,8 +33,8 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef _TC_TERMINATE_H
-#define _TC_TERMINATE_H
+#ifndef _TC_USEREXT_H
+#define _TC_USEREXT_H
#include <rtems.h>
@@ -42,12 +42,44 @@
extern "C" {
#endif
+void ThreadBeginExtension0( rtems_tcb *executing );
+
+bool ThreadCreateExtension0( rtems_tcb *executing, rtems_tcb *created );
+
+void ThreadDeleteExtension0( rtems_tcb *executing, rtems_tcb *deleted );
+
+void ThreadExittedExtension0( rtems_tcb *executing );
+
+void ThreadRestartExtension0( rtems_tcb *executing, rtems_tcb *restarted );
+
+void ThreadStartExtension0( rtems_tcb *executing, rtems_tcb *started );
+
+void ThreadSwitchExtension0( rtems_tcb *executing, rtems_tcb *heir );
+
+void ThreadTerminateExtension0( rtems_tcb *executing );
+
void FatalExtension0(
rtems_fatal_source source,
bool always_set_to_false,
rtems_fatal_code code
);
+void ThreadBeginExtension1( rtems_tcb *executing );
+
+bool ThreadCreateExtension1( rtems_tcb *executing, rtems_tcb *created );
+
+void ThreadDeleteExtension1( rtems_tcb *executing, rtems_tcb *deleted );
+
+void ThreadExittedExtension1( rtems_tcb *executing );
+
+void ThreadRestartExtension1( rtems_tcb *executing, rtems_tcb *restarted );
+
+void ThreadStartExtension1( rtems_tcb *executing, rtems_tcb *started );
+
+void ThreadSwitchExtension1( rtems_tcb *executing, rtems_tcb *heir );
+
+void ThreadTerminateExtension1( rtems_tcb *executing );
+
void FatalExtension1(
rtems_fatal_source source,
bool always_set_to_false,
@@ -58,4 +90,4 @@ void FatalExtension1(
}
#endif
-#endif /* _TC_TERMINATE_H */
+#endif /* _TC_USEREXT_H */
diff --git a/testsuites/validation/ts-default.h b/testsuites/validation/ts-default.h
index 3723e72ada..017db2edd7 100644
--- a/testsuites/validation/ts-default.h
+++ b/testsuites/validation/ts-default.h
@@ -157,7 +157,7 @@ static void task_stack_deallocate( void *stack )
#define CONFIGURE_MAXIMUM_TIMERS 3
-#define CONFIGURE_MAXIMUM_USER_EXTENSIONS 3
+#define CONFIGURE_MAXIMUM_USER_EXTENSIONS 5
#define CONFIGURE_MICROSECONDS_PER_TICK TEST_MICROSECONDS_PER_TICK
diff --git a/testsuites/validation/ts-terminate.c b/testsuites/validation/ts-terminate.c
index 491444a029..52676db6d9 100644
--- a/testsuites/validation/ts-terminate.c
+++ b/testsuites/validation/ts-terminate.c
@@ -52,7 +52,7 @@
#include "config.h"
#endif
-#include "tc-terminate.h"
+#include "tc-userext.h"
#include <rtems/test.h>
@@ -67,7 +67,7 @@
* @{
*/
-const char rtems_test_name[] = "Fatal";
+const char rtems_test_name[] = "Terminate";
#define CONFIGURE_MAXIMUM_PROCESSORS 2
diff --git a/testsuites/validation/ts-userext.c b/testsuites/validation/ts-userext.c
new file mode 100644
index 0000000000..5d41f52093
--- /dev/null
+++ b/testsuites/validation/ts-userext.c
@@ -0,0 +1,97 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/**
+ * @file
+ *
+ * @ingroup RTEMSTestSuiteTestsuitesUserext
+ */
+
+/*
+ * Copyright (C) 2021 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.
+ */
+
+/*
+ * This file is part of the RTEMS quality process and was automatically
+ * generated. If you find something that needs to be fixed or
+ * worded better please post a report or patch to an RTEMS mailing list
+ * or raise a bug report:
+ *
+ * https://www.rtems.org/bugs.html
+ *
+ * For information on updating and regenerating please refer to the How-To
+ * section in the Software Requirements Engineering chapter of the
+ * RTEMS Software Engineering manual. The manual is provided as a part of
+ * a release. For development sources please refer to the online
+ * documentation at:
+ *
+ * https://docs.rtems.org
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "tc-userext.h"
+
+#include <rtems/test.h>
+
+/**
+ * @defgroup RTEMSTestSuiteTestsuitesUserext spec:/testsuites/userext
+ *
+ * @ingroup RTEMSTestSuites
+ *
+ * @brief This validation test suite contains a test cases related to the
+ * invocation of user extensions.
+ *
+ * @{
+ */
+
+const char rtems_test_name[] = "Userext";
+
+#define CONFIGURE_MAXIMUM_PROCESSORS 2
+
+#define CONFIGURE_INITIAL_EXTENSIONS \
+ { \
+ .thread_begin = ThreadBeginExtension0, \
+ .thread_create = ThreadCreateExtension0, \
+ .thread_delete = ThreadDeleteExtension0, \
+ .thread_exitted = ThreadExittedExtension0, \
+ .thread_restart = ThreadRestartExtension0, \
+ .thread_start = ThreadStartExtension0, \
+ .thread_switch = ThreadSwitchExtension0, \
+ .thread_terminate = ThreadTerminateExtension0 \
+ }, { \
+ .thread_begin = ThreadBeginExtension1, \
+ .thread_create = ThreadCreateExtension1, \
+ .thread_delete = ThreadDeleteExtension1, \
+ .thread_exitted = ThreadExittedExtension1, \
+ .thread_restart = ThreadRestartExtension1, \
+ .thread_start = ThreadStartExtension1, \
+ .thread_switch = ThreadSwitchExtension1, \
+ .thread_terminate = ThreadTerminateExtension1 \
+ }
+
+#include "ts-default.h"
+
+/** @} */