forked from Imagelibrary/rtems
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:
@@ -210,7 +210,7 @@ void rtems_initialize_start_multitasking(void)
|
|||||||
{
|
{
|
||||||
_System_state_Set( SYSTEM_STATE_UP );
|
_System_state_Set( SYSTEM_STATE_UP );
|
||||||
|
|
||||||
_SMP_Request_other_cores_to_perform_first_context_switch();
|
_SMP_Request_start_multitasking();
|
||||||
|
|
||||||
_Thread_Start_multitasking();
|
_Thread_Start_multitasking();
|
||||||
|
|
||||||
|
|||||||
@@ -1462,10 +1462,10 @@ CPU_Counter_ticks _CPU_Counter_difference(
|
|||||||
|
|
||||||
#ifdef RTEMS_SMP
|
#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.
|
* 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
|
* initialization. All interrupt stacks are allocated at this point in case
|
||||||
* the CPU port allocates the interrupt stacks.
|
* the CPU port allocates the interrupt stacks.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -70,64 +70,83 @@ typedef struct Thread_Control_struct Thread_Control;
|
|||||||
#error "deferred FP switch not implemented for SMP"
|
#error "deferred FP switch not implemented for SMP"
|
||||||
#endif
|
#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 {
|
typedef enum {
|
||||||
/**
|
/**
|
||||||
* @brief The per CPU controls are initialized to zero.
|
* @brief The per CPU controls are initialized to zero.
|
||||||
*
|
*
|
||||||
* In this state the only valid field of the per CPU controls for secondary
|
* The boot processor executes the sequential boot code in this state. The
|
||||||
* processors is the per CPU state. The secondary processors should perform
|
* secondary processors should perform their basic initialization now and
|
||||||
* their basic initialization now and change into the
|
* change into the PER_CPU_STATE_READY_TO_START_MULTITASKING state once this
|
||||||
* PER_CPU_STATE_READY_TO_BEGIN_MULTITASKING state once this is complete.
|
* is complete.
|
||||||
*
|
|
||||||
* The owner of the per CPU state field is the secondary processor in this
|
|
||||||
* state.
|
|
||||||
*/
|
*/
|
||||||
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
|
* The secondary processor performed its basic initialization and is ready to
|
||||||
* receive inter-processor interrupts. Interrupt delivery must be disabled
|
* receive inter-processor interrupts. Interrupt delivery must be disabled
|
||||||
* in this state, but requested inter-processor interrupts must be recorded
|
* in this state, but requested inter-processor interrupts must be recorded
|
||||||
* and must be delivered once the secondary processor enables interrupts for
|
* 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
|
* 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
|
* 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
|
* for a change into the PER_CPU_STATE_REQUEST_START_MULTITASKING state set
|
||||||
* main processor once all secondary processors reached the
|
* by the boot processor once all secondary processors reached the
|
||||||
* PER_CPU_STATE_READY_TO_BEGIN_MULTITASKING state.
|
* PER_CPU_STATE_READY_TO_START_MULTITASKING state.
|
||||||
*
|
|
||||||
* The owner of the per CPU state field is the main processor in this 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
|
* a context switch to its heir thread. Secondary processors should now
|
||||||
* issue a context switch to the heir thread. This normally enables
|
* issue a context switch to the heir thread. This normally enables
|
||||||
* interrupts on the processor for the first time.
|
* 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.
|
* @brief Normal multitasking state.
|
||||||
*
|
|
||||||
* The owner of the per CPU state field is the secondary processor in this
|
|
||||||
* state.
|
|
||||||
*/
|
*/
|
||||||
PER_CPU_STATE_UP,
|
PER_CPU_STATE_UP,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This is the terminal state.
|
* @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_SHUTDOWN
|
||||||
} Per_CPU_State;
|
} 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_Initialize(void);
|
||||||
|
|
||||||
void _Per_CPU_Change_state(
|
void _Per_CPU_State_change(
|
||||||
Per_CPU_Control *per_cpu,
|
Per_CPU_Control *per_cpu,
|
||||||
Per_CPU_State new_state
|
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 ) */
|
#endif /* defined( RTEMS_SMP ) */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -108,8 +108,6 @@ static inline void _SMP_Inter_processor_interrupt_handler( void )
|
|||||||
_Per_CPU_Release_and_ISR_enable( self_cpu, level );
|
_Per_CPU_Release_and_ISR_enable( self_cpu, level );
|
||||||
|
|
||||||
if ( ( message & SMP_MESSAGE_SHUTDOWN ) != 0 ) {
|
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 );
|
rtems_fatal( RTEMS_FATAL_SOURCE_SMP, SMP_FATAL_SHUTDOWN );
|
||||||
/* does not continue past here */
|
/* does not continue past here */
|
||||||
}
|
}
|
||||||
@@ -143,27 +141,27 @@ void _SMP_Broadcast_message(
|
|||||||
#endif /* defined( RTEMS_SMP ) */
|
#endif /* defined( RTEMS_SMP ) */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Request other cores to perform first context switch.
|
* @brief Requests a multitasking start on all configured and available
|
||||||
*
|
* processors.
|
||||||
* Send message to other cores requesting them to perform
|
|
||||||
* their first context switch operation.
|
|
||||||
*/
|
*/
|
||||||
#if defined( RTEMS_SMP )
|
#if defined( RTEMS_SMP )
|
||||||
void _SMP_Request_other_cores_to_perform_first_context_switch( void );
|
void _SMP_Request_start_multitasking( void );
|
||||||
#else
|
#else
|
||||||
#define _SMP_Request_other_cores_to_perform_first_context_switch() \
|
#define _SMP_Request_start_multitasking() \
|
||||||
do { } while ( 0 )
|
do { } while ( 0 )
|
||||||
#endif
|
#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 )
|
#if defined( RTEMS_SMP )
|
||||||
void _SMP_Request_other_cores_to_shutdown( void );
|
void _SMP_Request_shutdown( void );
|
||||||
#else
|
#else
|
||||||
#define _SMP_Request_other_cores_to_shutdown() \
|
#define _SMP_Request_shutdown() \
|
||||||
do { } while ( 0 )
|
do { } while ( 0 )
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ void _Terminate(
|
|||||||
_ISR_Disable_without_giant( level );
|
_ISR_Disable_without_giant( level );
|
||||||
(void) level;
|
(void) level;
|
||||||
|
|
||||||
_SMP_Request_other_cores_to_shutdown();
|
_SMP_Request_shutdown();
|
||||||
|
|
||||||
_User_extensions_Fatal( the_source, is_internal, the_error );
|
_User_extensions_Fatal( the_source, is_internal, the_error );
|
||||||
|
|
||||||
|
|||||||
@@ -19,26 +19,156 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <rtems/score/percpu.h>
|
#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)
|
#if defined(RTEMS_SMP)
|
||||||
void _Per_CPU_Change_state(
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _Per_CPU_State_change(
|
||||||
Per_CPU_Control *per_cpu,
|
Per_CPU_Control *per_cpu,
|
||||||
Per_CPU_State new_state
|
Per_CPU_State new_state
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
per_cpu->state = new_state;
|
ISR_Level level;
|
||||||
_CPU_SMP_Processor_event_broadcast();
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _Per_CPU_Wait_for_state(
|
other_cpu->state = PER_CPU_STATE_SHUTDOWN;
|
||||||
const Per_CPU_Control *per_cpu,
|
|
||||||
Per_CPU_State desired_state
|
|
||||||
)
|
|
||||||
{
|
|
||||||
while ( per_cpu->state != desired_state ) {
|
|
||||||
_CPU_SMP_Processor_event_receive();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_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
|
#else
|
||||||
/*
|
/*
|
||||||
* On single core systems, we can efficiently directly access a single
|
* On single core systems, we can efficiently directly access a single
|
||||||
|
|||||||
@@ -24,10 +24,6 @@
|
|||||||
#include <rtems/score/threadimpl.h>
|
#include <rtems/score/threadimpl.h>
|
||||||
#include <rtems/config.h>
|
#include <rtems/config.h>
|
||||||
|
|
||||||
#if defined(RTEMS_DEBUG)
|
|
||||||
#include <rtems/bspIo.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void _SMP_Handler_initialize( void )
|
void _SMP_Handler_initialize( void )
|
||||||
{
|
{
|
||||||
uint32_t max_cpus = rtems_configuration_get_maximum_processors();
|
uint32_t max_cpus = rtems_configuration_get_maximum_processors();
|
||||||
@@ -47,21 +43,38 @@ void _SMP_Handler_initialize( void )
|
|||||||
_SMP_Processor_count = max_cpus;
|
_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 )
|
void _SMP_Start_multitasking_on_secondary_processor( void )
|
||||||
{
|
{
|
||||||
Per_CPU_Control *self_cpu = _Per_CPU_Get();
|
Per_CPU_Control *self_cpu = _Per_CPU_Get();
|
||||||
|
|
||||||
#if defined(RTEMS_DEBUG)
|
_Per_CPU_State_change( self_cpu, PER_CPU_STATE_READY_TO_START_MULTITASKING );
|
||||||
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 );
|
|
||||||
|
|
||||||
_Thread_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 )
|
void _SMP_Send_message( uint32_t cpu, uint32_t message )
|
||||||
{
|
{
|
||||||
Per_CPU_Control *per_cpu = _Per_CPU_Get_by_index( cpu );
|
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 );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ void _Thread_Start_multitasking( void )
|
|||||||
Thread_Control *heir;
|
Thread_Control *heir;
|
||||||
|
|
||||||
#if defined(RTEMS_SMP)
|
#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
|
* Threads begin execution in the _Thread_Handler() function. This
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ SUBDIRS += smp07
|
|||||||
SUBDIRS += smp08
|
SUBDIRS += smp08
|
||||||
SUBDIRS += smp09
|
SUBDIRS += smp09
|
||||||
SUBDIRS += smpatomic01
|
SUBDIRS += smpatomic01
|
||||||
|
SUBDIRS += smpfatal01
|
||||||
|
SUBDIRS += smpfatal02
|
||||||
SUBDIRS += smplock01
|
SUBDIRS += smplock01
|
||||||
SUBDIRS += smpmigration01
|
SUBDIRS += smpmigration01
|
||||||
SUBDIRS += smpschedule01
|
SUBDIRS += smpschedule01
|
||||||
|
|||||||
@@ -65,6 +65,8 @@ smp07/Makefile
|
|||||||
smp08/Makefile
|
smp08/Makefile
|
||||||
smp09/Makefile
|
smp09/Makefile
|
||||||
smpatomic01/Makefile
|
smpatomic01/Makefile
|
||||||
|
smpfatal01/Makefile
|
||||||
|
smpfatal02/Makefile
|
||||||
smplock01/Makefile
|
smplock01/Makefile
|
||||||
smpmigration01/Makefile
|
smpmigration01/Makefile
|
||||||
smppsxsignal01/Makefile
|
smppsxsignal01/Makefile
|
||||||
|
|||||||
19
testsuites/smptests/smpfatal01/Makefile.am
Normal file
19
testsuites/smptests/smpfatal01/Makefile.am
Normal 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
|
||||||
130
testsuites/smptests/smpfatal01/init.c
Normal file
130
testsuites/smptests/smpfatal01/init.c
Normal 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>
|
||||||
12
testsuites/smptests/smpfatal01/smpfatal01.doc
Normal file
12
testsuites/smptests/smpfatal01/smpfatal01.doc
Normal 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.
|
||||||
2
testsuites/smptests/smpfatal01/smpfatal01.scn
Normal file
2
testsuites/smptests/smpfatal01/smpfatal01.scn
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
*** TEST SMPFATAL 1 ***
|
||||||
|
*** END OF TEST SMPFATAL 1 ***
|
||||||
19
testsuites/smptests/smpfatal02/Makefile.am
Normal file
19
testsuites/smptests/smpfatal02/Makefile.am
Normal 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
|
||||||
135
testsuites/smptests/smpfatal02/init.c
Normal file
135
testsuites/smptests/smpfatal02/init.c
Normal 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>
|
||||||
12
testsuites/smptests/smpfatal02/smpfatal02.doc
Normal file
12
testsuites/smptests/smpfatal02/smpfatal02.doc
Normal 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.
|
||||||
2
testsuites/smptests/smpfatal02/smpfatal02.scn
Normal file
2
testsuites/smptests/smpfatal02/smpfatal02.scn
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
*** TEST SMPFATAL 2 ***
|
||||||
|
*** END OF TEST SMPFATAL 2 ***
|
||||||
Reference in New Issue
Block a user