/* * Copyright (C) 2012, 2020 embedded brains GmbH (http://www.embedded-brains.de) * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at * http://www.rtems.org/license/LICENSE. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include const char rtems_test_name[] = "SPINTRCRITICAL 18"; #define WAKE_UP RTEMS_EVENT_0 #define PRIORITY_LOW 3 #define PRIORITY_MIDDLE 2 #define PRIORITY_HIGH 1 typedef struct { rtems_id middle_priority_task; rtems_id high_priority_task; bool high_priority_task_activated; volatile bool early; volatile bool switching; volatile bool late; long potential_hits; } test_context; static void wake_up( rtems_id task ) { rtems_status_code sc; sc = rtems_event_send( task, WAKE_UP ); T_quiet_rsc_success( sc ); } static void wait_for_wake_up( void ) { rtems_status_code sc; rtems_event_set events; sc = rtems_event_receive( WAKE_UP, RTEMS_EVENT_ALL | RTEMS_WAIT, RTEMS_NO_TIMEOUT, &events ); T_quiet_rsc_success( sc ); T_quiet_eq_u32( events, WAKE_UP ); } static T_interrupt_test_state active_high_priority_task( void *arg ) { test_context *ctx = arg; T_interrupt_test_state state; state = T_interrupt_test_get_state(); if ( state != T_INTERRUPT_TEST_ACTION ) { return T_INTERRUPT_TEST_CONTINUE; } T_quiet_false( ctx->high_priority_task_activated ); ctx->high_priority_task_activated = true; wake_up( ctx->high_priority_task ); if ( ctx->early ) { state = T_INTERRUPT_TEST_EARLY; } else if ( ctx->late ) { state = T_INTERRUPT_TEST_LATE; } else { ++ctx->potential_hits; if ( ctx->potential_hits > 13 ) { state = T_INTERRUPT_TEST_DONE; } else { state = T_INTERRUPT_TEST_CONTINUE; } } return state; } static void middle_priority_task( rtems_task_argument arg ) { test_context *ctx = (test_context *) arg; while ( true ) { wait_for_wake_up(); ctx->late = true; T_quiet_false( ctx->high_priority_task_activated ); } } static void high_priority_task( rtems_task_argument arg ) { test_context *ctx = (test_context *) arg; while ( true ) { wait_for_wake_up(); T_quiet_true( ctx->high_priority_task_activated ); ctx->high_priority_task_activated = false; } } static void prepare( void *arg ) { test_context *ctx = arg; ctx->early = true; ctx->switching = false; ctx->late = false; } static void action( void *arg ) { test_context *ctx = arg; ctx->early = false; wake_up( ctx->middle_priority_task ); } static void blocked( void *arg ) { test_context *ctx = arg; T_interrupt_test_state state; state = T_interrupt_test_change_state( T_INTERRUPT_TEST_ACTION, T_INTERRUPT_TEST_LATE ); if ( state == T_INTERRUPT_TEST_ACTION ) { ctx->switching = true; T_busy( 100 ); ctx->switching = false; } } static const T_interrupt_test_config config = { .prepare = prepare, .action = action, .interrupt = active_high_priority_task, .blocked = blocked, .max_iteration_count = 10000 }; T_TEST_CASE(InterruptDuringThreadDispatch) { T_interrupt_test_state state; test_context ctx; rtems_status_code sc; memset( &ctx, 0, sizeof( ctx ) ); sc = rtems_task_create( rtems_build_name( 'H', 'I', 'G', 'H' ), PRIORITY_HIGH, RTEMS_MINIMUM_STACK_SIZE, RTEMS_DEFAULT_MODES, RTEMS_DEFAULT_ATTRIBUTES, &ctx.high_priority_task ); T_assert_rsc_success( sc ); sc = rtems_task_start( ctx.high_priority_task, high_priority_task, (rtems_task_argument) &ctx ); T_assert_rsc_success( sc ); sc = rtems_task_create( rtems_build_name( 'M', 'I', 'D', 'L' ), PRIORITY_MIDDLE, RTEMS_MINIMUM_STACK_SIZE, RTEMS_DEFAULT_MODES, RTEMS_DEFAULT_ATTRIBUTES, &ctx.middle_priority_task ); T_assert_rsc_success( sc ); sc = rtems_task_start( ctx.middle_priority_task, middle_priority_task, (rtems_task_argument) &ctx ); T_assert_rsc_success( sc ); state = T_interrupt_test( &config, &ctx ); T_eq_int( state, T_INTERRUPT_TEST_DONE ); sc = rtems_task_delete( ctx.high_priority_task ); T_rsc_success( sc ); sc = rtems_task_delete( ctx.middle_priority_task ); T_rsc_success( sc ); } static rtems_task Init( rtems_task_argument argument ) { rtems_test_run( argument, TEST_STATE ); } #define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER #define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER #define CONFIGURE_MICROSECONDS_PER_TICK 1000 #define CONFIGURE_MAXIMUM_TASKS 3 #define CONFIGURE_INIT_TASK_PRIORITY PRIORITY_LOW #define CONFIGURE_INIT_TASK_ATTRIBUTES RTEMS_DEFAULT_ATTRIBUTES #define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES #define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION #define CONFIGURE_RTEMS_INIT_TASKS_TABLE #define CONFIGURE_INIT #include