[PATCH v2] score: SMP initialization and shutdown changes
Gedare Bloom
gedare at rtems.org
Thu Feb 20 17:36:58 UTC 2014
What RTEMS configure and BSPs do you test this on?
On Thu, Feb 20, 2014 at 11:22 AM, Sebastian Huber
<sebastian.huber at embedded-brains.de> wrote:
> Rename _SMP_Request_other_cores_to_perform_first_context_switch() into
> _SMP_Request_start_multitasking() since this requests now a multitasking
> start on all configured and available processors. The name corresponds
> _Thread_Start_multitasking() and
> _SMP_Start_multitasking_on_secondary_processor() actions issued in
> response to this request. Move in source file to right place.
>
> Rename PER_CPU_STATE_READY_TO_BEGIN_MULTITASKING into
> PER_CPU_STATE_READY_TO_START_MULTITASKING.
>
> Rename PER_CPU_STATE_BEGIN_MULTITASKING into
> PER_CPU_STATE_REQUEST_START_MULTITASKING.
>
> Rename _SMP_Request_other_cores_to_shutdown() into
> _SMP_Request_shutdown().
>
> Add a per-CPU state lock to protect all changes. This was necessary to
> offer a controlled shutdown of the system (atomic read/writes alone are
> not sufficient for this kind of synchronization).
>
> Add documentation for Per_CPU_State.
>
> Delete debug output.
>
> New tests smptests/smpfatal01 and smptests/smpfatal02.
> ---
> cpukit/sapi/src/exinit.c | 2 +-
> cpukit/score/include/rtems/score/percpu.h | 82 ++++++++------
> cpukit/score/include/rtems/score/smpimpl.h | 22 ++--
> cpukit/score/src/interr.c | 2 +-
> cpukit/score/src/percpu.c | 158 ++++++++++++++++++++++--
> cpukit/score/src/smp.c | 77 ++++---------
> cpukit/score/src/threadstartmultitasking.c | 2 +-
> testsuites/smptests/Makefile.am | 2 +
> testsuites/smptests/configure.ac | 2 +
> testsuites/smptests/smpfatal01/Makefile.am | 19 +++
> testsuites/smptests/smpfatal01/init.c | 130 ++++++++++++++++++++
> testsuites/smptests/smpfatal01/smpfatal01.doc | 12 ++
> testsuites/smptests/smpfatal01/smpfatal01.scn | 2 +
> testsuites/smptests/smpfatal02/Makefile.am | 19 +++
> testsuites/smptests/smpfatal02/init.c | 135 +++++++++++++++++++++
> testsuites/smptests/smpfatal02/smpfatal02.doc | 12 ++
> testsuites/smptests/smpfatal02/smpfatal02.scn | 2 +
> 17 files changed, 563 insertions(+), 117 deletions(-)
> create mode 100644 testsuites/smptests/smpfatal01/Makefile.am
> create mode 100644 testsuites/smptests/smpfatal01/init.c
> create mode 100644 testsuites/smptests/smpfatal01/smpfatal01.doc
> create mode 100644 testsuites/smptests/smpfatal01/smpfatal01.scn
> create mode 100644 testsuites/smptests/smpfatal02/Makefile.am
> create mode 100644 testsuites/smptests/smpfatal02/init.c
> create mode 100644 testsuites/smptests/smpfatal02/smpfatal02.doc
> create mode 100644 testsuites/smptests/smpfatal02/smpfatal02.scn
>
> diff --git a/cpukit/sapi/src/exinit.c b/cpukit/sapi/src/exinit.c
> index d265455..ee1c7fd 100644
> --- a/cpukit/sapi/src/exinit.c
> +++ b/cpukit/sapi/src/exinit.c
> @@ -210,7 +210,7 @@ void rtems_initialize_start_multitasking(void)
> {
> _System_state_Set( SYSTEM_STATE_UP );
>
> - _SMP_Request_other_cores_to_perform_first_context_switch();
> + _SMP_Request_start_multitasking();
>
> _Thread_Start_multitasking();
>
> diff --git a/cpukit/score/include/rtems/score/percpu.h b/cpukit/score/include/rtems/score/percpu.h
> index 4c46b50..ca9185e 100644
> --- a/cpukit/score/include/rtems/score/percpu.h
> +++ b/cpukit/score/include/rtems/score/percpu.h
> @@ -70,64 +70,83 @@ typedef struct Thread_Control_struct Thread_Control;
> #error "deferred FP switch not implemented for SMP"
> #endif
>
> +/**
> + * @brief State of a processor.
> + *
> + * The processor state controls the life cycle of processors at the lowest
> + * level. No multi-threading or other high-level concepts matter here.
> + *
> + * State changes must be initiated via _Per_CPU_Change_state(). This function
> + * may not return in case someone requested a shutdown. The
> + * _SMP_Send_message() function will be used to notify other processors about
> + * state changes if the other processor is in the up state.
> + *
> + * Due to the sequential nature of the basic system initialization one
> + * processor has a special role. It is the processor executing the boot_card()
> + * function. This processor is called the boot processor. All other
> + * processors are called secondary.
> + *
> + * @dot
> + * digraph states {
> + * i [label="PER_CPU_STATE_INITIAL"];
> + * rdy [label="PER_CPU_STATE_READY_TO_START_MULTITASKING"];
> + * reqsm [label="PER_CPU_STATE_REQUEST_START_MULTITASKING"];
> + * u [label="PER_CPU_STATE_UP"];
> + * s [label="PER_CPU_STATE_SHUTDOWN"];
> + * i -> rdy [label="processor\ncompleted initialization"];
> + * rdy -> reqsm [label="boot processor\ncompleted initialization"];
> + * reqsm -> u [label="processor\nstarts multitasking"];
> + * i -> s;
> + * rdy -> s;
> + * reqsm -> s;
> + * u -> s;
> + * }
> + * @enddot
> + */
> typedef enum {
> /**
> * @brief The per CPU controls are initialized to zero.
> *
> - * In this state the only valid field of the per CPU controls for secondary
> - * processors is the per CPU state. The secondary processors should perform
> - * their basic initialization now and change into the
> - * PER_CPU_STATE_READY_TO_BEGIN_MULTITASKING state once this is complete.
> - *
> - * The owner of the per CPU state field is the secondary processor in this
> - * state.
> + * The boot processor executes the sequential boot code in this state. The
> + * secondary processors should perform their basic initialization now and
> + * change into the PER_CPU_STATE_READY_TO_START_MULTITASKING state once this
> + * is complete.
> */
> - PER_CPU_STATE_BEFORE_INITIALIZATION,
> + PER_CPU_STATE_INITIAL,
>
> /**
> - * @brief Secondary processor is ready to begin multitasking.
> + * @brief Processor is ready to start multitasking.
> *
> * The secondary processor performed its basic initialization and is ready to
> * receive inter-processor interrupts. Interrupt delivery must be disabled
> * in this state, but requested inter-processor interrupts must be recorded
> * and must be delivered once the secondary processor enables interrupts for
> - * the first time. The main processor will wait for all secondary processors
> + * the first time. The boot processor will wait for all secondary processors
> * to change into this state. In case a secondary processor does not reach
> * this state the system will not start. The secondary processors wait now
> - * for a change into the PER_CPU_STATE_BEGIN_MULTITASKING state set by the
> - * main processor once all secondary processors reached the
> - * PER_CPU_STATE_READY_TO_BEGIN_MULTITASKING state.
> - *
> - * The owner of the per CPU state field is the main processor in this state.
> + * for a change into the PER_CPU_STATE_REQUEST_START_MULTITASKING state set
> + * by the boot processor once all secondary processors reached the
> + * PER_CPU_STATE_READY_TO_START_MULTITASKING state.
> */
> - PER_CPU_STATE_READY_TO_BEGIN_MULTITASKING,
> + PER_CPU_STATE_READY_TO_START_MULTITASKING,
>
> /**
> - * @brief Multitasking begin of secondary processor is requested.
> + * @brief Multitasking start of processor is requested.
> *
> - * The main processor completed system initialization and is about to perform
> + * The boot processor completed system initialization and is about to perform
> * a context switch to its heir thread. Secondary processors should now
> * issue a context switch to the heir thread. This normally enables
> * interrupts on the processor for the first time.
> - *
> - * The owner of the per CPU state field is the secondary processor in this
> - * state.
> */
> - PER_CPU_STATE_BEGIN_MULTITASKING,
> + PER_CPU_STATE_REQUEST_START_MULTITASKING,
>
> /**
> * @brief Normal multitasking state.
> - *
> - * The owner of the per CPU state field is the secondary processor in this
> - * state.
> */
> PER_CPU_STATE_UP,
>
> /**
> * @brief This is the terminal state.
> - *
> - * The owner of the per CPU state field is the secondary processor in this
> - * state.
> */
> PER_CPU_STATE_SHUTDOWN
> } Per_CPU_State;
> @@ -313,16 +332,11 @@ static inline void _Per_CPU_Send_interrupt( const Per_CPU_Control *per_cpu )
> */
> void _Per_CPU_Initialize(void);
>
> -void _Per_CPU_Change_state(
> +void _Per_CPU_State_change(
> Per_CPU_Control *per_cpu,
> Per_CPU_State new_state
> );
>
> -void _Per_CPU_Wait_for_state(
> - const Per_CPU_Control *per_cpu,
> - Per_CPU_State desired_state
> -);
> -
> #endif /* defined( RTEMS_SMP ) */
>
> /*
> diff --git a/cpukit/score/include/rtems/score/smpimpl.h b/cpukit/score/include/rtems/score/smpimpl.h
> index d68af43..da08cf5 100644
> --- a/cpukit/score/include/rtems/score/smpimpl.h
> +++ b/cpukit/score/include/rtems/score/smpimpl.h
> @@ -108,8 +108,6 @@ static inline void _SMP_Inter_processor_interrupt_handler( void )
> _Per_CPU_Release_and_ISR_enable( self_cpu, level );
>
> if ( ( message & SMP_MESSAGE_SHUTDOWN ) != 0 ) {
> - _Per_CPU_Change_state( self_cpu, PER_CPU_STATE_SHUTDOWN );
> -
> rtems_fatal( RTEMS_FATAL_SOURCE_SMP, SMP_FATAL_SHUTDOWN );
> /* does not continue past here */
> }
> @@ -143,27 +141,27 @@ void _SMP_Broadcast_message(
> #endif /* defined( RTEMS_SMP ) */
>
> /**
> - * @brief Request other cores to perform first context switch.
> - *
> - * Send message to other cores requesting them to perform
> - * their first context switch operation.
> + * @brief Requests a multitasking start on all configured and available
> + * processors.
> */
> #if defined( RTEMS_SMP )
> - void _SMP_Request_other_cores_to_perform_first_context_switch( void );
> + void _SMP_Request_start_multitasking( void );
> #else
> - #define _SMP_Request_other_cores_to_perform_first_context_switch() \
> + #define _SMP_Request_start_multitasking() \
> do { } while ( 0 )
> #endif
>
> /**
> - * @brief Request other cores to shutdown.
> + * @brief Requests a shutdown of all processors.
> + *
> + * This function is a part of the system termination procedure.
> *
> - * Send message to other cores requesting them to shutdown.
> + * @see _Terminate().
> */
> #if defined( RTEMS_SMP )
> - void _SMP_Request_other_cores_to_shutdown( void );
> + void _SMP_Request_shutdown( void );
> #else
> - #define _SMP_Request_other_cores_to_shutdown() \
> + #define _SMP_Request_shutdown() \
> do { } while ( 0 )
> #endif
>
> diff --git a/cpukit/score/src/interr.c b/cpukit/score/src/interr.c
> index c2a9fbe..11578a6 100644
> --- a/cpukit/score/src/interr.c
> +++ b/cpukit/score/src/interr.c
> @@ -39,7 +39,7 @@ void _Terminate(
> _ISR_Disable_without_giant( level );
> (void) level;
>
> - _SMP_Request_other_cores_to_shutdown();
> + _SMP_Request_shutdown();
>
> _User_extensions_Fatal( the_source, is_internal, the_error );
>
> diff --git a/cpukit/score/src/percpu.c b/cpukit/score/src/percpu.c
> index c68f378..3a7a845 100644
> --- a/cpukit/score/src/percpu.c
> +++ b/cpukit/score/src/percpu.c
> @@ -19,26 +19,156 @@
> #endif
>
> #include <rtems/score/percpu.h>
> +#include <rtems/score/assert.h>
> +#include <rtems/score/smpimpl.h>
> +#include <rtems/config.h>
> +#include <rtems/fatal.h>
>
> #if defined(RTEMS_SMP)
> - void _Per_CPU_Change_state(
> - Per_CPU_Control *per_cpu,
> - Per_CPU_State new_state
> - )
> - {
> - per_cpu->state = new_state;
> - _CPU_SMP_Processor_event_broadcast();
> +
> +static SMP_lock_Control _Per_CPU_State_lock = SMP_LOCK_INITIALIZER;
> +
> +static ISR_Level _Per_CPU_State_acquire( void )
> +{
> + ISR_Level level;
> +
> + _SMP_lock_ISR_disable_and_acquire( &_Per_CPU_State_lock, level );
> +
> + return level;
> +}
> +
> +static void _Per_CPU_State_release( ISR_Level level )
> +{
> + _SMP_lock_Release_and_ISR_enable( &_Per_CPU_State_lock, level );
> +}
> +
> +static void _Per_CPU_State_busy_wait(
> + const Per_CPU_Control *per_cpu,
> + Per_CPU_State new_state
> +)
> +{
> + Per_CPU_State state = per_cpu->state;
> +
> + switch ( new_state ) {
> + case PER_CPU_STATE_REQUEST_START_MULTITASKING:
> + while (
> + state != PER_CPU_STATE_READY_TO_START_MULTITASKING
> + && state != PER_CPU_STATE_SHUTDOWN
> + ) {
> + _CPU_SMP_Processor_event_receive();
> + state = per_cpu->state;
> + }
> + break;
> + case PER_CPU_STATE_UP:
> + while (
> + state != PER_CPU_STATE_REQUEST_START_MULTITASKING
> + && state != PER_CPU_STATE_SHUTDOWN
> + ) {
> + _CPU_SMP_Processor_event_receive();
> + state = per_cpu->state;
> + }
> + break;
> + default:
> + /* No need to wait */
> + break;
> + }
> +}
> +
> +static Per_CPU_State _Per_CPU_State_get_next(
> + Per_CPU_State current_state,
> + Per_CPU_State new_state
> +)
> +{
> + switch ( current_state ) {
> + case PER_CPU_STATE_INITIAL:
> + switch ( new_state ) {
> + case PER_CPU_STATE_READY_TO_START_MULTITASKING:
> + case PER_CPU_STATE_SHUTDOWN:
> + /* Change is acceptable */
> + break;
> + default:
> + new_state = PER_CPU_STATE_SHUTDOWN;
> + break;
> + }
> + break;
> + case PER_CPU_STATE_READY_TO_START_MULTITASKING:
> + switch ( new_state ) {
> + case PER_CPU_STATE_REQUEST_START_MULTITASKING:
> + case PER_CPU_STATE_SHUTDOWN:
> + /* Change is acceptable */
> + break;
> + default:
> + new_state = PER_CPU_STATE_SHUTDOWN;
> + break;
> + }
> + break;
> + case PER_CPU_STATE_REQUEST_START_MULTITASKING:
> + switch ( new_state ) {
> + case PER_CPU_STATE_UP:
> + case PER_CPU_STATE_SHUTDOWN:
> + /* Change is acceptable */
> + break;
> + default:
> + new_state = PER_CPU_STATE_SHUTDOWN;
> + break;
> + }
> + break;
> + default:
> + new_state = PER_CPU_STATE_SHUTDOWN;
> + break;
> }
>
> - void _Per_CPU_Wait_for_state(
> - const Per_CPU_Control *per_cpu,
> - Per_CPU_State desired_state
> - )
> - {
> - while ( per_cpu->state != desired_state ) {
> - _CPU_SMP_Processor_event_receive();
> + return new_state;
> +}
> +
> +void _Per_CPU_State_change(
> + Per_CPU_Control *per_cpu,
> + Per_CPU_State new_state
> +)
> +{
> + ISR_Level level;
> + Per_CPU_State next_state;
> +
> + _Per_CPU_State_busy_wait( per_cpu, new_state );
> +
> + level = _Per_CPU_State_acquire();
> + next_state = _Per_CPU_State_get_next( per_cpu->state, new_state );
> + per_cpu->state = next_state;
> +
> + if ( next_state == PER_CPU_STATE_SHUTDOWN ) {
> + uint32_t ncpus = rtems_configuration_get_maximum_processors();
> + uint32_t cpu;
> +
> + for ( cpu = 0 ; cpu < ncpus ; ++cpu ) {
> + Per_CPU_Control *other_cpu = _Per_CPU_Get_by_index( cpu );
> +
> + if ( per_cpu != other_cpu ) {
> + switch ( other_cpu->state ) {
> + case PER_CPU_STATE_UP:
> + _SMP_Send_message( cpu, SMP_MESSAGE_SHUTDOWN );
> + break;
> + default:
> + /* Nothing to do */
> + break;
> + }
> +
> + other_cpu->state = PER_CPU_STATE_SHUTDOWN;
> + }
> }
> }
> +
> + _CPU_SMP_Processor_event_broadcast();
> +
> + _Per_CPU_State_release( level );
> +
> + if (
> + next_state == PER_CPU_STATE_SHUTDOWN
> + && new_state != PER_CPU_STATE_SHUTDOWN
> + ) {
> + rtems_fatal( RTEMS_FATAL_SOURCE_SMP, SMP_FATAL_SHUTDOWN );
> + }
> +}
> +
> #else
> /*
> * On single core systems, we can efficiently directly access a single
> diff --git a/cpukit/score/src/smp.c b/cpukit/score/src/smp.c
> index 59036eb..0f63223 100644
> --- a/cpukit/score/src/smp.c
> +++ b/cpukit/score/src/smp.c
> @@ -24,10 +24,6 @@
> #include <rtems/score/threadimpl.h>
> #include <rtems/config.h>
>
> -#if defined(RTEMS_DEBUG)
> - #include <rtems/bspIo.h>
> -#endif
> -
> void _SMP_Handler_initialize( void )
> {
> uint32_t max_cpus = rtems_configuration_get_maximum_processors();
> @@ -47,21 +43,38 @@ void _SMP_Handler_initialize( void )
> _SMP_Processor_count = max_cpus;
> }
>
> -void _SMP_Start_multitasking_on_secondary_processor( void )
> +void _SMP_Request_start_multitasking( void )
> {
> Per_CPU_Control *self_cpu = _Per_CPU_Get();
> + uint32_t ncpus = _SMP_Get_processor_count();
> + uint32_t cpu;
> +
> + _Per_CPU_State_change( self_cpu, PER_CPU_STATE_READY_TO_START_MULTITASKING );
>
> - #if defined(RTEMS_DEBUG)
> - printk( "Made it to %d -- ", _Per_CPU_Get_index( self_cpu ) );
> - #endif
> + for ( cpu = 0 ; cpu < ncpus ; ++cpu ) {
> + Per_CPU_Control *per_cpu = _Per_CPU_Get_by_index( cpu );
> +
> + _Per_CPU_State_change( per_cpu, PER_CPU_STATE_REQUEST_START_MULTITASKING );
> + }
> +}
>
> - _Per_CPU_Change_state( self_cpu, PER_CPU_STATE_READY_TO_BEGIN_MULTITASKING );
> +void _SMP_Start_multitasking_on_secondary_processor( void )
> +{
> + Per_CPU_Control *self_cpu = _Per_CPU_Get();
>
> - _Per_CPU_Wait_for_state( self_cpu, PER_CPU_STATE_BEGIN_MULTITASKING );
> + _Per_CPU_State_change( self_cpu, PER_CPU_STATE_READY_TO_START_MULTITASKING );
>
> _Thread_Start_multitasking();
> }
>
> +void _SMP_Request_shutdown( void )
> +{
> + uint32_t self = _SMP_Get_current_processor();
> + Per_CPU_Control *self_cpu = _Per_CPU_Get_by_index( self );
> +
> + _Per_CPU_State_change( self_cpu, PER_CPU_STATE_SHUTDOWN );
> +}
> +
> void _SMP_Send_message( uint32_t cpu, uint32_t message )
> {
> Per_CPU_Control *per_cpu = _Per_CPU_Get_by_index( cpu );
> @@ -88,47 +101,3 @@ void _SMP_Broadcast_message( uint32_t message )
> }
> }
> }
> -
> -void _SMP_Request_other_cores_to_perform_first_context_switch( void )
> -{
> - uint32_t self = _SMP_Get_current_processor();
> - uint32_t ncpus = _SMP_Get_processor_count();
> - uint32_t cpu;
> -
> - for ( cpu = 0 ; cpu < ncpus ; ++cpu ) {
> - Per_CPU_Control *per_cpu = _Per_CPU_Get_by_index( cpu );
> -
> - if ( cpu != self ) {
> - _Per_CPU_Wait_for_state(
> - per_cpu,
> - PER_CPU_STATE_READY_TO_BEGIN_MULTITASKING
> - );
> -
> - _Per_CPU_Change_state( per_cpu, PER_CPU_STATE_BEGIN_MULTITASKING );
> - }
> - }
> -}
> -
> -void _SMP_Request_other_cores_to_shutdown( void )
> -{
> - uint32_t self = _SMP_Get_current_processor();
> -
> - /*
> - * Do not use _SMP_Get_processor_count() since this value might be not
> - * initialized yet. For example due to a fatal error in the middle of
> - * _CPU_SMP_Initialize().
> - */
> - uint32_t ncpus = rtems_configuration_get_maximum_processors();
> -
> - uint32_t cpu;
> -
> - for ( cpu = 0 ; cpu < ncpus ; ++cpu ) {
> - if ( cpu != self ) {
> - const Per_CPU_Control *per_cpu = _Per_CPU_Get_by_index( cpu );
> -
> - if ( per_cpu->state != PER_CPU_STATE_BEFORE_INITIALIZATION ) {
> - _SMP_Send_message( cpu, SMP_MESSAGE_SHUTDOWN );
> - }
> - }
> - }
> -}
> diff --git a/cpukit/score/src/threadstartmultitasking.c b/cpukit/score/src/threadstartmultitasking.c
> index a61a51c..b9cdaf8 100644
> --- a/cpukit/score/src/threadstartmultitasking.c
> +++ b/cpukit/score/src/threadstartmultitasking.c
> @@ -26,7 +26,7 @@ void _Thread_Start_multitasking( void )
> Thread_Control *heir;
>
> #if defined(RTEMS_SMP)
> - _Per_CPU_Change_state( self_cpu, PER_CPU_STATE_UP );
> + _Per_CPU_State_change( self_cpu, PER_CPU_STATE_UP );
>
> /*
> * Threads begin execution in the _Thread_Handler() function. This
> diff --git a/testsuites/smptests/Makefile.am b/testsuites/smptests/Makefile.am
> index 023b7e9..8422f3a 100644
> --- a/testsuites/smptests/Makefile.am
> +++ b/testsuites/smptests/Makefile.am
> @@ -11,6 +11,8 @@ SUBDIRS += smp07
> SUBDIRS += smp08
> SUBDIRS += smp09
> SUBDIRS += smpatomic01
> +SUBDIRS += smpfatal01
> +SUBDIRS += smpfatal02
> SUBDIRS += smplock01
> SUBDIRS += smpmigration01
> SUBDIRS += smpschedule01
> diff --git a/testsuites/smptests/configure.ac b/testsuites/smptests/configure.ac
> index 5c68772..19e32f3 100644
> --- a/testsuites/smptests/configure.ac
> +++ b/testsuites/smptests/configure.ac
> @@ -65,6 +65,8 @@ smp07/Makefile
> smp08/Makefile
> smp09/Makefile
> smpatomic01/Makefile
> +smpfatal01/Makefile
> +smpfatal02/Makefile
> smplock01/Makefile
> smpmigration01/Makefile
> smppsxsignal01/Makefile
> diff --git a/testsuites/smptests/smpfatal01/Makefile.am b/testsuites/smptests/smpfatal01/Makefile.am
> new file mode 100644
> index 0000000..2aaee2b
> --- /dev/null
> +++ b/testsuites/smptests/smpfatal01/Makefile.am
> @@ -0,0 +1,19 @@
> +rtems_tests_PROGRAMS = smpfatal01
> +smpfatal01_SOURCES = init.c
> +
> +dist_rtems_tests_DATA = smpfatal01.scn smpfatal01.doc
> +
> +include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP at .cfg
> +include $(top_srcdir)/../automake/compile.am
> +include $(top_srcdir)/../automake/leaf.am
> +
> +AM_CPPFLAGS += -I$(top_srcdir)/../support/include
> +
> +LINK_OBJS = $(smpfatal01_OBJECTS)
> +LINK_LIBS = $(smpfatal01_LDLIBS)
> +
> +smpfatal01$(EXEEXT): $(smpfatal01_OBJECTS) $(smpfatal01_DEPENDENCIES)
> + @rm -f smpfatal01$(EXEEXT)
> + $(make-exe)
> +
> +include $(top_srcdir)/../automake/local.am
> diff --git a/testsuites/smptests/smpfatal01/init.c b/testsuites/smptests/smpfatal01/init.c
> new file mode 100644
> index 0000000..c78b29f
> --- /dev/null
> +++ b/testsuites/smptests/smpfatal01/init.c
> @@ -0,0 +1,130 @@
> +/*
> + * Copyright (c) 2014 embedded brains GmbH. All rights reserved.
> + *
> + * embedded brains GmbH
> + * Dornierstr. 4
> + * 82178 Puchheim
> + * Germany
> + * <rtems at 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.com/license/LICENSE.
> + */
> +
> +#ifdef HAVE_CONFIG_H
> + #include "config.h"
> +#endif
> +
> +#include <rtems.h>
> +#include <rtems/score/percpu.h>
> +#include <rtems/score/smpimpl.h>
> +
> +#include <assert.h>
> +#include <stdlib.h>
> +
> +#define MAX_CPUS 32
> +
> +static uint32_t main_cpu;
> +
> +static void Init(rtems_task_argument arg)
> +{
> + assert(0);
> +}
> +
> +static void end_of_test(void)
> +{
> + printk( "*** END OF TEST SMPFATAL 1 ***\n" );
> +}
> +
> +static void fatal_extension(
> + rtems_fatal_source source,
> + bool is_internal,
> + rtems_fatal_code code
> +)
> +{
> + if (source == RTEMS_FATAL_SOURCE_SMP) {
> + uint32_t self = rtems_smp_get_current_processor();
> +
> + assert(!is_internal);
> + assert(code == SMP_FATAL_SHUTDOWN);
> +
> + if (self == main_cpu) {
> + uint32_t cpu;
> +
> + for (cpu = 0; cpu < MAX_CPUS; ++cpu) {
> + const Per_CPU_Control *per_cpu = _Per_CPU_Get_by_index( cpu );
> + Per_CPU_State state = per_cpu->state;
> +
> + assert(state == PER_CPU_STATE_SHUTDOWN);
> + }
> +
> + end_of_test();
> + }
> + }
> +}
> +
> +static rtems_status_code test_driver_init(
> + rtems_device_major_number major,
> + rtems_device_minor_number minor,
> + void *arg
> +)
> +{
> + uint32_t self = rtems_smp_get_current_processor();
> + uint32_t cpu_count = rtems_smp_get_processor_count();
> + uint32_t cpu;
> +
> + printk("\n\n*** TEST SMPFATAL 1 ***\n");
> +
> + assert(rtems_configuration_get_maximum_processors() == MAX_CPUS);
> +
> + main_cpu = self;
> +
> + for (cpu = 0; cpu < MAX_CPUS; ++cpu) {
> + const Per_CPU_Control *per_cpu = _Per_CPU_Get_by_index( cpu );
> + Per_CPU_State state = per_cpu->state;
> +
> + if (cpu == self) {
> + assert(state == PER_CPU_STATE_INITIAL);
> + } else if (cpu < cpu_count) {
> + assert(
> + state == PER_CPU_STATE_INITIAL
> + || state == PER_CPU_STATE_READY_TO_START_MULTITASKING
> + );
> + } else {
> + assert(state == PER_CPU_STATE_INITIAL);
> + }
> + }
> +
> + if (cpu_count > 1) {
> + uint32_t other = (self + 1) % cpu_count;
> + Per_CPU_Control *per_cpu = _Per_CPU_Get_by_index( other );
> +
> + per_cpu->state = PER_CPU_STATE_SHUTDOWN;
> + } else {
> + end_of_test();
> + exit(0);
> + }
> +
> + return RTEMS_SUCCESSFUL;
> +}
> +
> +#define CONFIGURE_APPLICATION_DOES_NOT_NEED_CLOCK_DRIVER
> +#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
> +
> +#define CONFIGURE_APPLICATION_EXTRA_DRIVERS \
> + { .initialization_entry = test_driver_init }
> +
> +#define CONFIGURE_INITIAL_EXTENSIONS { .fatal = fatal_extension }
> +
> +#define CONFIGURE_SMP_APPLICATION
> +
> +#define CONFIGURE_SMP_MAXIMUM_PROCESSORS MAX_CPUS
> +
> +#define CONFIGURE_MAXIMUM_TASKS 1
> +
> +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
> +
> +#define CONFIGURE_INIT
> +
> +#include <rtems/confdefs.h>
> diff --git a/testsuites/smptests/smpfatal01/smpfatal01.doc b/testsuites/smptests/smpfatal01/smpfatal01.doc
> new file mode 100644
> index 0000000..c037cfe
> --- /dev/null
> +++ b/testsuites/smptests/smpfatal01/smpfatal01.doc
> @@ -0,0 +1,12 @@
> +This file describes the directives and concepts tested by this test set.
> +
> +test set name: smpfatal01
> +
> +directives:
> +
> + - _Per_CPU_State_change()
> +
> +concepts:
> +
> + - Ensure that the system termination in case of shutdown detection at a
> + secondary processors works during driver initialization.
> diff --git a/testsuites/smptests/smpfatal01/smpfatal01.scn b/testsuites/smptests/smpfatal01/smpfatal01.scn
> new file mode 100644
> index 0000000..0b67121
> --- /dev/null
> +++ b/testsuites/smptests/smpfatal01/smpfatal01.scn
> @@ -0,0 +1,2 @@
> +*** TEST SMPFATAL 1 ***
> +*** END OF TEST SMPFATAL 1 ***
> diff --git a/testsuites/smptests/smpfatal02/Makefile.am b/testsuites/smptests/smpfatal02/Makefile.am
> new file mode 100644
> index 0000000..bbce3b7
> --- /dev/null
> +++ b/testsuites/smptests/smpfatal02/Makefile.am
> @@ -0,0 +1,19 @@
> +rtems_tests_PROGRAMS = smpfatal02
> +smpfatal02_SOURCES = init.c
> +
> +dist_rtems_tests_DATA = smpfatal02.scn smpfatal02.doc
> +
> +include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP at .cfg
> +include $(top_srcdir)/../automake/compile.am
> +include $(top_srcdir)/../automake/leaf.am
> +
> +AM_CPPFLAGS += -I$(top_srcdir)/../support/include
> +
> +LINK_OBJS = $(smpfatal02_OBJECTS)
> +LINK_LIBS = $(smpfatal02_LDLIBS)
> +
> +smpfatal02$(EXEEXT): $(smpfatal02_OBJECTS) $(smpfatal02_DEPENDENCIES)
> + @rm -f smpfatal02$(EXEEXT)
> + $(make-exe)
> +
> +include $(top_srcdir)/../automake/local.am
> diff --git a/testsuites/smptests/smpfatal02/init.c b/testsuites/smptests/smpfatal02/init.c
> new file mode 100644
> index 0000000..1e8da26
> --- /dev/null
> +++ b/testsuites/smptests/smpfatal02/init.c
> @@ -0,0 +1,135 @@
> +/*
> + * Copyright (c) 2014 embedded brains GmbH. All rights reserved.
> + *
> + * embedded brains GmbH
> + * Dornierstr. 4
> + * 82178 Puchheim
> + * Germany
> + * <rtems at 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.com/license/LICENSE.
> + */
> +
> +#ifdef HAVE_CONFIG_H
> + #include "config.h"
> +#endif
> +
> +#include <rtems.h>
> +#include <rtems/score/percpu.h>
> +#include <rtems/score/smpimpl.h>
> +
> +#include <assert.h>
> +#include <stdlib.h>
> +
> +#define MAX_CPUS 32
> +
> +static uint32_t main_cpu;
> +
> +static void Init(rtems_task_argument arg)
> +{
> + assert(0);
> +}
> +
> +static void end_of_test(void)
> +{
> + printk( "*** END OF TEST SMPFATAL 2 ***\n" );
> +}
> +
> +static void fatal_extension(
> + rtems_fatal_source source,
> + bool is_internal,
> + rtems_fatal_code code
> +)
> +{
> + if (
> + source == RTEMS_FATAL_SOURCE_APPLICATION
> + || source == RTEMS_FATAL_SOURCE_SMP
> + ) {
> + uint32_t self = rtems_smp_get_current_processor();
> +
> + assert(!is_internal);
> +
> + if (self == main_cpu) {
> + uint32_t cpu;
> +
> + assert(source == RTEMS_FATAL_SOURCE_APPLICATION);
> + assert(code == 0xdeadbeef);
> +
> + for (cpu = 0; cpu < MAX_CPUS; ++cpu) {
> + const Per_CPU_Control *per_cpu = _Per_CPU_Get_by_index( cpu );
> + Per_CPU_State state = per_cpu->state;
> +
> + assert(state == PER_CPU_STATE_SHUTDOWN);
> + }
> +
> + end_of_test();
> + } else {
> + assert(source == RTEMS_FATAL_SOURCE_SMP);
> + assert(code == SMP_FATAL_SHUTDOWN);
> + }
> + }
> +}
> +
> +static rtems_status_code test_driver_init(
> + rtems_device_major_number major,
> + rtems_device_minor_number minor,
> + void *arg
> +)
> +{
> + uint32_t self = rtems_smp_get_current_processor();
> + uint32_t cpu_count = rtems_smp_get_processor_count();
> + uint32_t cpu;
> +
> + printk("\n\n*** TEST SMPFATAL 2 ***\n");
> +
> + assert(rtems_configuration_get_maximum_processors() == MAX_CPUS);
> +
> + main_cpu = self;
> +
> + for (cpu = 0; cpu < MAX_CPUS; ++cpu) {
> + const Per_CPU_Control *per_cpu = _Per_CPU_Get_by_index( cpu );
> + Per_CPU_State state = per_cpu->state;
> +
> + if (cpu == self) {
> + assert(state == PER_CPU_STATE_INITIAL);
> + } else if (cpu < cpu_count) {
> + assert(
> + state == PER_CPU_STATE_INITIAL
> + || state == PER_CPU_STATE_READY_TO_START_MULTITASKING
> + );
> + } else {
> + assert(state == PER_CPU_STATE_INITIAL);
> + }
> + }
> +
> + if (cpu_count > 1) {
> + rtems_fatal(RTEMS_FATAL_SOURCE_APPLICATION, 0xdeadbeef);
> + } else {
> + end_of_test();
> + exit(0);
> + }
> +
> + return RTEMS_SUCCESSFUL;
> +}
> +
> +#define CONFIGURE_APPLICATION_DOES_NOT_NEED_CLOCK_DRIVER
> +#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
> +
> +#define CONFIGURE_APPLICATION_EXTRA_DRIVERS \
> + { .initialization_entry = test_driver_init }
> +
> +#define CONFIGURE_INITIAL_EXTENSIONS { .fatal = fatal_extension }
> +
> +#define CONFIGURE_SMP_APPLICATION
> +
> +#define CONFIGURE_SMP_MAXIMUM_PROCESSORS MAX_CPUS
> +
> +#define CONFIGURE_MAXIMUM_TASKS 1
> +
> +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
> +
> +#define CONFIGURE_INIT
> +
> +#include <rtems/confdefs.h>
> diff --git a/testsuites/smptests/smpfatal02/smpfatal02.doc b/testsuites/smptests/smpfatal02/smpfatal02.doc
> new file mode 100644
> index 0000000..9e2e002
> --- /dev/null
> +++ b/testsuites/smptests/smpfatal02/smpfatal02.doc
> @@ -0,0 +1,12 @@
> +This file describes the directives and concepts tested by this test set.
> +
> +test set name: smpfatal02
> +
> +directives:
> +
> + - _Per_CPU_State_change()
> +
> +concepts:
> +
> + - Ensure that the system termination in case of fatal errors during driver
> + initialization works.
> diff --git a/testsuites/smptests/smpfatal02/smpfatal02.scn b/testsuites/smptests/smpfatal02/smpfatal02.scn
> new file mode 100644
> index 0000000..cde11a0
> --- /dev/null
> +++ b/testsuites/smptests/smpfatal02/smpfatal02.scn
> @@ -0,0 +1,2 @@
> +*** TEST SMPFATAL 2 ***
> +*** END OF TEST SMPFATAL 2 ***
> --
> 1.7.7
>
> _______________________________________________
> rtems-devel mailing list
> rtems-devel at rtems.org
> http://www.rtems.org/mailman/listinfo/rtems-devel
More information about the devel
mailing list