score: SMP initialization and shutdown changes

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.
This commit is contained in:
Sebastian Huber
2014-02-18 13:40:39 +01:00
parent 7fe0561526
commit 7336be9d78
18 changed files with 566 additions and 120 deletions

View File

@@ -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();

View File

@@ -1462,10 +1462,10 @@ CPU_Counter_ticks _CPU_Counter_difference(
#ifdef RTEMS_SMP
/**
* @brief Performs CPU specific SMP initialization in the context of the main
* @brief Performs CPU specific SMP initialization in the context of the boot
* processor.
*
* This function is invoked on the main processor by RTEMS during
* This function is invoked on the boot processor by RTEMS during
* initialization. All interrupt stacks are allocated at this point in case
* the CPU port allocates the interrupt stacks.
*

View File

@@ -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 ) */
/*

View File

@@ -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.
*
* Send message to other cores requesting them to shutdown.
* This function is a part of the system termination procedure.
*
* @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

View File

@@ -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 );

View File

@@ -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

View File

@@ -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_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 );
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 );
}
}
void _SMP_Start_multitasking_on_secondary_processor( void )
{
Per_CPU_Control *self_cpu = _Per_CPU_Get();
#if defined(RTEMS_DEBUG)
printk( "Made it to %d -- ", _Per_CPU_Get_index( self_cpu ) );
#endif
_Per_CPU_Change_state( self_cpu, PER_CPU_STATE_READY_TO_BEGIN_MULTITASKING );
_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 );
}
}
}
}

View File

@@ -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

View File

@@ -11,6 +11,8 @@ SUBDIRS += smp07
SUBDIRS += smp08
SUBDIRS += smp09
SUBDIRS += smpatomic01
SUBDIRS += smpfatal01
SUBDIRS += smpfatal02
SUBDIRS += smplock01
SUBDIRS += smpmigration01
SUBDIRS += smpschedule01

View File

@@ -65,6 +65,8 @@ smp07/Makefile
smp08/Makefile
smp09/Makefile
smpatomic01/Makefile
smpfatal01/Makefile
smpfatal02/Makefile
smplock01/Makefile
smpmigration01/Makefile
smppsxsignal01/Makefile

View File

@@ -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@.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

View File

@@ -0,0 +1,130 @@
/*
* Copyright (c) 2014 embedded brains GmbH. All rights reserved.
*
* embedded brains GmbH
* Dornierstr. 4
* 82178 Puchheim
* Germany
* <rtems@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>

View File

@@ -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.

View File

@@ -0,0 +1,2 @@
*** TEST SMPFATAL 1 ***
*** END OF TEST SMPFATAL 1 ***

View File

@@ -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@.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

View File

@@ -0,0 +1,135 @@
/*
* Copyright (c) 2014 embedded brains GmbH. All rights reserved.
*
* embedded brains GmbH
* Dornierstr. 4
* 82178 Puchheim
* Germany
* <rtems@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>

View File

@@ -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.

View File

@@ -0,0 +1,2 @@
*** TEST SMPFATAL 2 ***
*** END OF TEST SMPFATAL 2 ***