/* 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 #include #include #include "tc-userext.h" #include "tx-support.h" #include /** * @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(); } /** @} */