diff options
Diffstat (limited to 'testsuites/validation/tc-userext.c')
-rw-r--r-- | testsuites/validation/tc-userext.c | 918 |
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(); +} + +/** @} */ |