summaryrefslogtreecommitdiffstats
path: root/testsuites/validation/tc-userext.c
diff options
context:
space:
mode:
Diffstat (limited to 'testsuites/validation/tc-userext.c')
-rw-r--r--testsuites/validation/tc-userext.c918
1 files changed, 918 insertions, 0 deletions
diff --git a/testsuites/validation/tc-userext.c b/testsuites/validation/tc-userext.c
new file mode 100644
index 0000000000..192be30669
--- /dev/null
+++ b/testsuites/validation/tc-userext.c
@@ -0,0 +1,918 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/**
+ * @file
+ *
+ * @ingroup RtemsUserextValUserext
+ */
+
+/*
+ * Copyright (C) 2021 embedded brains GmbH & Co. KG
+ *
+ * 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 RtemsUserextValUserext spec:/rtems/userext/val/userext
+ *
+ * @ingroup TestsuitesUserext
+ *
+ * @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.
+ *
+ * - Create five dynamic extensions. Let an idle thread return from its 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.
+ *
+ * @{
+ */
+
+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();
+
+ if ( GetExecuting()->is_idle ) {
+ SetSelfPriority( RTEMS_MAXIMUM_PRIORITY );
+ _CPU_Thread_Idle_body( 0 );
+ } else {
+ 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();
+}
+
+void *IdleBody( uintptr_t arg )
+{
+ rtems_event_set events;
+
+ do {
+ events = PollAnyEvents();
+ } while ( events == 0 );
+
+ (void) StartTestCase( THREAD_EXITTED );
+ return (void *) arg;
+}
+
+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
+};
+
+/**
+ * @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 );
+}
+
+/**
+ * @brief Create five dynamic extensions. Let an idle thread return from its
+ * entry. Delete three dynamic extension during the thread exitted
+ * invocation. Clean up the used resources.
+ */
+static void RtemsUserextValUserext_Action_7( void )
+{
+ rtems_tcb *thread;
+ rtems_id id;
+
+ /* ID of idle thread of processor 0 */
+ id = 0x09010001;
+ thread = GetThread( id );
+ SendEvents( id, RTEMS_EVENT_0 );
+ SetPriority( id, PRIO_HIGH );
+
+ /*
+ * 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 );
+}
+
+/**
+ * @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();
+ RtemsUserextValUserext_Action_7();
+}
+
+/** @} */