The per-CPU states which control the SMP system initialization were added quite early during the SMP support development. Replace this initial implementation with a simplified one. There is no longer a global SMP lock required which serialized the state changes of all processors. The new implementation better integrates with the per-CPU jobs. --- cpukit/include/rtems/score/percpu.h | 42 ++--- cpukit/include/rtems/score/smpimpl.h | 60 +++++-- cpukit/score/src/percpu.c | 151 +----------------- cpukit/score/src/smp.c | 133 +++++++++++++-- cpukit/score/src/smpmulticastaction.c | 36 ++--- cpukit/score/src/threadstartmultitasking.c | 4 +- testsuites/smptests/smpfatal01/init.c | 57 +++++-- testsuites/smptests/smpfatal01/smpfatal01.doc | 3 +- testsuites/smptests/smpfatal02/init.c | 21 ++- testsuites/smptests/smpfatal02/smpfatal02.doc | 3 +- 10 files changed, 260 insertions(+), 250 deletions(-)
diff --git a/cpukit/include/rtems/score/percpu.h b/cpukit/include/rtems/score/percpu.h index e79596c244..f72339620d 100644 --- a/cpukit/include/rtems/score/percpu.h +++ b/cpukit/include/rtems/score/percpu.h @@ -102,15 +102,18 @@ struct Scheduler_Context; * 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_State_change(). 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. + * The state of a processor is indicated by the Per_CPU_Control::state membe. + * The current state of a processor can be get by _Per_CPU_Get_state(). Only + * the processor associated with the control may change its state using + * _Per_CPU_Set_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. + * processors are called secondary. The boot processor uses + * _SMP_Request_start_multitasking() to indicate that processors should start + * multiprocessing. Secondary processors will wait for this request in + * _SMP_Start_multitasking_on_secondary_processor(). * * @dot * digraph states { @@ -150,22 +153,12 @@ typedef enum { * 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_REQUEST_START_MULTITASKING state set - * by the boot processor once all secondary processors reached the - * PER_CPU_STATE_READY_TO_START_MULTITASKING state. + * for a change into the PER_CPU_STATE_UP state set requested by the boot + * processor through ::_SMP_Ready_to_start_multitasking once all secondary + * processors reached the PER_CPU_STATE_READY_TO_START_MULTITASKING state. */ PER_CPU_STATE_READY_TO_START_MULTITASKING, - /** - * @brief Multitasking start of processor is requested. - * - * 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. - */ - PER_CPU_STATE_REQUEST_START_MULTITASKING, - /** * @brief Normal multitasking state. */ @@ -547,11 +540,12 @@ typedef struct Per_CPU_Control { char *data; /** - * @brief Indicates the current state of the CPU. + * @brief Indicates the current state of the processor. * - * This member is protected by the _Per_CPU_State_lock lock. + * Only the processor associated with this control is allowed to change + * this member. * - * @see _Per_CPU_State_change(). + * @see _Per_CPU_Get_state() and _Per_CPU_Set_state(). */ Atomic_Uint state; @@ -801,6 +795,7 @@ static inline void _Per_CPU_Set_state( Per_CPU_State state ) { + _Assert( cpu_self == _Per_CPU_Get() ); _Atomic_Store_uint( &cpu_self->state, (unsigned int) state, @@ -808,11 +803,6 @@ static inline void _Per_CPU_Set_state( ); } -void _Per_CPU_State_change( - Per_CPU_Control *cpu, - Per_CPU_State new_state -); - /** * @brief Waits for a processor to change into a non-initial state. * diff --git a/cpukit/include/rtems/score/smpimpl.h b/cpukit/include/rtems/score/smpimpl.h index 32704d7288..2770402562 100644 --- a/cpukit/include/rtems/score/smpimpl.h +++ b/cpukit/include/rtems/score/smpimpl.h @@ -50,6 +50,12 @@ extern "C" { */ #define SMP_MESSAGE_PERFORM_JOBS 0x2UL +/** + * @brief SMP message to force the message processing in + * _SMP_Try_to_process_message(). + */ +#define SMP_MESSAGE_FORCE_PROCESSING 0x1UL + /** * @brief SMP fatal codes. */ @@ -99,6 +105,15 @@ static inline void _SMP_Fatal( SMP_Fatal_code code ) */ extern Processor_mask _SMP_Online_processors; +/** + * @brief Indicates if the system is ready to start multitasking. + * + * Only the boot processor is allowed to change this object. If the object has + * a non-zero value and no fatal error occurred, then secondary processors + * should call _Thread_Start_multitasking() to start multiprocessing. + */ +extern Atomic_Uint _SMP_Ready_to_start_multitasking; + /** * @brief Performs high-level initialization of a secondary processor and runs * the application threads. @@ -129,12 +144,44 @@ RTEMS_NO_RETURN void _SMP_Start_multitasking_on_secondary_processor( Per_CPU_Control *cpu_self ); +/** + * @brief Processes the SMP message. + * + * @param[in, out] cpu_self is the processor control of the processor executing + * this function. + * + * @return Returns the processed message. + */ +long unsigned _SMP_Process_message( + Per_CPU_Control *cpu_self, + long unsigned message +); + +/** + * @brief Tries to process the current SMP message. + * + * This function may be used in busy wait loops. + * + * @param cpu_self is the processor control of the processor executing this + * function. + * + * @param message is used to check if the SMP message processing should be + * carried out. If it is not equal to zero, then _SMP_Process_message() is + * called if a newly fetched message. This parameter is not used to process + * the message. + */ +void _SMP_Try_to_process_message( + Per_CPU_Control *cpu_self, + unsigned long message +); + /** * @brief Interrupts handler for inter-processor interrupts. * - * @param[in, out] cpu_self The cpu control for the operation. + * @param[in, out] cpu_self is the processor control of the processor executing + * this function. * - * @return The received message. + * @return Returns the processed message. */ static inline long unsigned _SMP_Inter_processor_interrupt_handler( Per_CPU_Control *cpu_self @@ -155,14 +202,7 @@ static inline long unsigned _SMP_Inter_processor_interrupt_handler( ); if ( RTEMS_PREDICT_FALSE( message != 0 ) ) { - if ( ( message & SMP_MESSAGE_SHUTDOWN ) != 0 ) { - _SMP_Fatal( SMP_FATAL_SHUTDOWN_RESPONSE ); - /* does not continue past here */ - } - - if ( ( message & SMP_MESSAGE_PERFORM_JOBS ) != 0 ) { - _Per_CPU_Perform_jobs( cpu_self ); - } + return _SMP_Process_message( cpu_self, message ); } return message; diff --git a/cpukit/score/src/percpu.c b/cpukit/score/src/percpu.c index 7fbc1c8637..611f55c0c1 100644 --- a/cpukit/score/src/percpu.c +++ b/cpukit/score/src/percpu.c @@ -3,8 +3,8 @@ * * @ingroup RTEMSScorePerCPU * - * @brief This source file contains a definition of ::_Per_CPU_Information and - * the implementation of _Per_CPU_State_change(). + * @brief This source file contains the uniprocessor definition of + * ::_Per_CPU_Information and the some static assertions. */ /* @@ -21,10 +21,6 @@ #endif #include <rtems/score/percpu.h> -#include <rtems/score/assert.h> -#include <rtems/score/isrlock.h> -#include <rtems/score/smpimpl.h> -#include <rtems/config.h> RTEMS_STATIC_ASSERT( sizeof( CPU_Uint32ptr ) >= sizeof( uintptr_t ), @@ -36,148 +32,7 @@ RTEMS_STATIC_ASSERT( CPU_Uint32ptr_greater_equal_uint32_t ); -#if defined(RTEMS_SMP) - -ISR_LOCK_DEFINE( static, _Per_CPU_State_lock, "Per-CPU State" ) - -static void _Per_CPU_State_acquire( ISR_lock_Context *lock_context ) -{ - _ISR_lock_ISR_disable_and_acquire( &_Per_CPU_State_lock, lock_context ); -} - -static void _Per_CPU_State_release( ISR_lock_Context *lock_context ) -{ - _ISR_lock_Release_and_ISR_enable( &_Per_CPU_State_lock, lock_context ); -} - -static void _Per_CPU_State_busy_wait( - Per_CPU_Control *cpu, - Per_CPU_State new_state -) -{ - Per_CPU_State state; - - state = _Per_CPU_Get_state( cpu ); - - switch ( new_state ) { - case PER_CPU_STATE_REQUEST_START_MULTITASKING: - while ( - state != PER_CPU_STATE_READY_TO_START_MULTITASKING - && state != PER_CPU_STATE_SHUTDOWN - ) { - _Per_CPU_Perform_jobs( cpu ); - state = _Per_CPU_Get_state( cpu ); - } - break; - case PER_CPU_STATE_UP: - while ( - state != PER_CPU_STATE_REQUEST_START_MULTITASKING - && state != PER_CPU_STATE_SHUTDOWN - ) { - _Per_CPU_Perform_jobs( cpu ); - state = _Per_CPU_Get_state( cpu ); - } - 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 *cpu, - Per_CPU_State new_state -) -{ - ISR_lock_Context lock_context; - Per_CPU_State next_state; - - _Per_CPU_State_busy_wait( cpu, new_state ); - - _Per_CPU_State_acquire( &lock_context ); - - next_state = _Per_CPU_State_get_next( _Per_CPU_Get_state( cpu ), new_state ); - _Per_CPU_Set_state( cpu, next_state ); - - if ( next_state == PER_CPU_STATE_SHUTDOWN ) { - uint32_t cpu_max = rtems_configuration_get_maximum_processors(); - uint32_t cpu_index; - - for ( cpu_index = 0 ; cpu_index < cpu_max ; ++cpu_index ) { - Per_CPU_Control *cpu_other = _Per_CPU_Get_by_index( cpu_index ); - - if ( cpu_other != cpu ) { - switch ( _Per_CPU_Get_state( cpu_other ) ) { - case PER_CPU_STATE_UP: - _SMP_Send_message( cpu_index, SMP_MESSAGE_SHUTDOWN ); - break; - default: - /* Nothing to do */ - break; - } - - _Per_CPU_Set_state( cpu_other, PER_CPU_STATE_SHUTDOWN ); - } - } - } - - _Per_CPU_State_release( &lock_context ); - - if ( - next_state == PER_CPU_STATE_SHUTDOWN - && new_state != PER_CPU_STATE_SHUTDOWN - ) { - _SMP_Fatal( SMP_FATAL_SHUTDOWN ); - } -} -#else +#if !defined(RTEMS_SMP) /* * On single core systems, we can efficiently directly access a single * statically allocated per cpu structure. And the fields are initialized diff --git a/cpukit/score/src/smp.c b/cpukit/score/src/smp.c index 0488464da0..bf53876dab 100644 --- a/cpukit/score/src/smp.c +++ b/cpukit/score/src/smp.c @@ -4,12 +4,13 @@ * @ingroup RTEMSScoreSMP * * @brief This source file contains the definition of ::_SMP_Online_processors - * and ::_SMP_Processor_maximum and the implementation of - * _SMP_Handler_initialize(), _SMP_Request_shutdown(), - * _SMP_Request_start_multitasking(), _SMP_Send_message(), - * _SMP_Send_message_broadcast(), _SMP_Send_message_multicast(), - * _SMP_Should_start_processor(), and - * _SMP_Start_multitasking_on_secondary_processor(). + * ::_SMP_Ready_to_start_multitasking, and ::_SMP_Processor_maximum and the + * implementation of _SMP_Handler_initialize(), _SMP_Process_message(), + * _SMP_Request_shutdown(), _SMP_Request_start_multitasking(), + * _SMP_Send_message(), _SMP_Send_message_broadcast(), + * _SMP_Send_message_multicast(), _SMP_Should_start_processor(), + * _SMP_Start_multitasking_on_secondary_processor(), and + * _SMP_Try_to_process_message(). */ /* @@ -37,6 +38,8 @@ Processor_mask _SMP_Online_processors; +Atomic_Uint _SMP_Ready_to_start_multitasking; + uint32_t _SMP_Processor_maximum; static const Scheduler_Assignment *_Scheduler_Get_initial_assignment( @@ -159,20 +162,38 @@ void _SMP_Request_start_multitasking( void ) uint32_t cpu_max; uint32_t cpu_index; - cpu_self = _Per_CPU_Get(); - _Per_CPU_State_change( cpu_self, PER_CPU_STATE_READY_TO_START_MULTITASKING ); - cpu_max = _SMP_Get_processor_maximum(); + cpu_self = _Per_CPU_Get(); + /* + * Wait until all other online processors reached the + * PER_CPU_STATE_READY_TO_START_MULTITASKING state. The waiting is done + * without a timeout. If secondary processors cannot reach this state, then + * it is expected that they indicate this failure with an + * ::SMP_MESSAGE_SHUTDOWN message or reset the system. + */ for ( cpu_index = 0 ; cpu_index < cpu_max ; ++cpu_index ) { Per_CPU_Control *cpu; cpu = _Per_CPU_Get_by_index( cpu_index ); - if ( _Per_CPU_Is_processor_online( cpu ) ) { - _Per_CPU_State_change( cpu, PER_CPU_STATE_REQUEST_START_MULTITASKING ); + if ( cpu != cpu_self && _Per_CPU_Is_processor_online( cpu ) ) { + while ( + _Per_CPU_Get_state( cpu ) != PER_CPU_STATE_READY_TO_START_MULTITASKING + ) { + _SMP_Try_to_process_message( + cpu_self, + _Atomic_Load_ulong( &cpu_self->message, ATOMIC_ORDER_RELAXED ) + ); + } } } + + _Atomic_Store_uint( + &_SMP_Ready_to_start_multitasking, + 0xffffffffU, + ATOMIC_ORDER_RELEASE + ); } bool _SMP_Should_start_processor( uint32_t cpu_index ) @@ -183,6 +204,22 @@ bool _SMP_Should_start_processor( uint32_t cpu_index ) return _Scheduler_Should_start_processor( assignment ); } +static void _SMP_Wait_for_start_multitasking( Per_CPU_Control *cpu_self ) +{ + unsigned int ready; + + do { + _SMP_Try_to_process_message( + cpu_self, + _Atomic_Load_ulong( &cpu_self->message, ATOMIC_ORDER_RELAXED ) + ); + ready = (Per_CPU_State) _Atomic_Load_uint( + &_SMP_Ready_to_start_multitasking, + ATOMIC_ORDER_ACQUIRE + ); + } while ( ready == 0 ); +} + void _SMP_Start_multitasking_on_secondary_processor( Per_CPU_Control *cpu_self ) @@ -199,28 +236,92 @@ void _SMP_Start_multitasking_on_secondary_processor( _SMP_Fatal( SMP_FATAL_MULTITASKING_START_ON_UNASSIGNED_PROCESSOR ); } - _Per_CPU_State_change( cpu_self, PER_CPU_STATE_READY_TO_START_MULTITASKING ); - + _Per_CPU_Set_state( cpu_self, PER_CPU_STATE_READY_TO_START_MULTITASKING ); + _SMP_Wait_for_start_multitasking( cpu_self ); _Thread_Start_multitasking(); } void _SMP_Request_shutdown( void ) { ISR_Level level; + uint32_t cpu_max; + uint32_t cpu_index_self; + uint32_t cpu_index; _ISR_Local_disable( level ); (void) level; - _Per_CPU_State_change( _Per_CPU_Get(), PER_CPU_STATE_SHUTDOWN ); + cpu_max = _SMP_Processor_configured_maximum; + cpu_index_self = _SMP_Get_current_processor(); + + for ( cpu_index = 0 ; cpu_index < cpu_max ; ++cpu_index ) { + Per_CPU_Control *cpu; + + cpu = _Per_CPU_Get_by_index( cpu_index ); + + if ( cpu_index == cpu_index_self ) { + _Per_CPU_Set_state( cpu, PER_CPU_STATE_SHUTDOWN ); + } else { + _Atomic_Fetch_or_ulong( + &cpu->message, + SMP_MESSAGE_SHUTDOWN, + ATOMIC_ORDER_RELEASE + ); + + if ( _Per_CPU_Get_state( cpu ) == PER_CPU_STATE_UP ) { + _CPU_SMP_Send_interrupt( cpu_index ); + } + } + } +} + +long unsigned _SMP_Process_message( + Per_CPU_Control *cpu_self, + long unsigned message +) +{ + if ( ( message & SMP_MESSAGE_SHUTDOWN ) != 0 ) { + /* Check the state to prevent recursive shutdowns */ + if ( _Per_CPU_Get_state( cpu_self ) != PER_CPU_STATE_SHUTDOWN ) { + _Per_CPU_Set_state( cpu_self, PER_CPU_STATE_SHUTDOWN ); + _SMP_Fatal( SMP_FATAL_SHUTDOWN_RESPONSE ); + } + } + + if ( ( message & SMP_MESSAGE_PERFORM_JOBS ) != 0 ) { + _Per_CPU_Perform_jobs( cpu_self ); + } +} + +void _SMP_Try_to_process_message( + Per_CPU_Control *cpu_self, + unsigned long message +) +{ + if ( message != 0 ) { + /* Fetch the actual message */ + message = _Atomic_Exchange_ulong( + &cpu_self->message, + 0, + ATOMIC_ORDER_ACQUIRE + ); + + _SMP_Process_message( cpu_self, message ); + } } void _SMP_Send_message( uint32_t cpu_index, unsigned long message ) { Per_CPU_Control *cpu = _Per_CPU_Get_by_index( cpu_index ); - _Atomic_Fetch_or_ulong( &cpu->message, message, ATOMIC_ORDER_RELEASE ); + (void) _Atomic_Fetch_or_ulong( + &cpu->message, message, + ATOMIC_ORDER_RELEASE + ); - _CPU_SMP_Send_interrupt( cpu_index ); + if ( _Per_CPU_Get_state( cpu ) == PER_CPU_STATE_UP ) { + _CPU_SMP_Send_interrupt( cpu_index ); + } } void _SMP_Send_message_broadcast( unsigned long message ) diff --git a/cpukit/score/src/smpmulticastaction.c b/cpukit/score/src/smpmulticastaction.c index 5d65ef14ca..8dbdef80c7 100644 --- a/cpukit/score/src/smpmulticastaction.c +++ b/cpukit/score/src/smpmulticastaction.c @@ -92,27 +92,6 @@ void _Per_CPU_Add_job( Per_CPU_Control *cpu, Per_CPU_Job *job ) _Per_CPU_Jobs_release_and_ISR_enable( cpu, &lock_context ); } -static void _Per_CPU_Try_perform_jobs( Per_CPU_Control *cpu_self ) -{ - unsigned long message; - - message = _Atomic_Load_ulong( &cpu_self->message, ATOMIC_ORDER_RELAXED ); - - if ( ( message & SMP_MESSAGE_PERFORM_JOBS ) != 0 ) { - bool success; - - success = _Atomic_Compare_exchange_ulong( - &cpu_self->message, &message, - message & ~SMP_MESSAGE_PERFORM_JOBS, ATOMIC_ORDER_RELAXED, - ATOMIC_ORDER_RELAXED - ); - - if ( success ) { - _Per_CPU_Perform_jobs( cpu_self ); - } - } -} - void _Per_CPU_Wait_for_job( const Per_CPU_Control *cpu, const Per_CPU_Job *job @@ -122,17 +101,22 @@ void _Per_CPU_Wait_for_job( _Atomic_Load_ulong( &job->done, ATOMIC_ORDER_ACQUIRE ) != PER_CPU_JOB_DONE ) { + Per_CPU_Control *cpu_self; + switch ( _Per_CPU_Get_state( cpu ) ) { case PER_CPU_STATE_INITIAL: case PER_CPU_STATE_READY_TO_START_MULTITASKING: - case PER_CPU_STATE_REQUEST_START_MULTITASKING: case PER_CPU_STATE_UP: /* - * Calling this function with the current processor is intentional. - * We have to perform our own jobs here in case inter-processor - * interrupts are not working. + * Calling this function with the current processor is intentional. We + * have to perform our own jobs here in case inter-processor interrupts + * are not working. */ - _Per_CPU_Try_perform_jobs( _Per_CPU_Get() ); + cpu_self = _Per_CPU_Get(); + _SMP_Try_to_process_message( + cpu_self, + _Atomic_Load_ulong( &cpu_self->message, ATOMIC_ORDER_RELAXED ) + ); break; default: _SMP_Fatal( SMP_FATAL_WRONG_CPU_STATE_TO_PERFORM_JOBS ); diff --git a/cpukit/score/src/threadstartmultitasking.c b/cpukit/score/src/threadstartmultitasking.c index 094a535394..9fa52a58ac 100644 --- a/cpukit/score/src/threadstartmultitasking.c +++ b/cpukit/score/src/threadstartmultitasking.c @@ -22,6 +22,7 @@ #include <rtems/score/threadimpl.h> #include <rtems/score/assert.h> +#include <rtems/score/smpimpl.h> void _Thread_Start_multitasking( void ) { @@ -29,7 +30,8 @@ void _Thread_Start_multitasking( void ) Thread_Control *heir; #if defined(RTEMS_SMP) - _Per_CPU_State_change( cpu_self, PER_CPU_STATE_UP ); + _Per_CPU_Set_state( cpu_self, PER_CPU_STATE_UP ); + _SMP_Try_to_process_message( cpu_self, SMP_MESSAGE_FORCE_PROCESSING ); /* * Threads begin execution in the _Thread_Handler() function. This diff --git a/testsuites/smptests/smpfatal01/init.c b/testsuites/smptests/smpfatal01/init.c index 0fd5f3fc46..6ee08cf653 100644 --- a/testsuites/smptests/smpfatal01/init.c +++ b/testsuites/smptests/smpfatal01/init.c @@ -32,6 +32,8 @@ const char rtems_test_name[] = "SMPFATAL 1"; static uint32_t main_cpu; +static uint32_t other_cpu; + static SMP_barrier_Control barrier = SMP_BARRIER_CONTROL_INITIALIZER; static void Init(rtems_task_argument arg) @@ -45,35 +47,59 @@ static void fatal_extension( rtems_fatal_code code ) { - SMP_barrier_State barrier_state = SMP_BARRIER_STATE_INITIALIZER; + assert(!always_set_to_false); if (source == RTEMS_FATAL_SOURCE_SMP) { + SMP_barrier_State barrier_state = SMP_BARRIER_STATE_INITIALIZER; + uint32_t cpu_count = rtems_scheduler_get_processor_maximum(); uint32_t self = rtems_scheduler_get_processor(); - assert(!always_set_to_false); - assert(code == SMP_FATAL_SHUTDOWN); + if (self == other_cpu) { + assert(code == SMP_FATAL_SHUTDOWN); + } else { + assert(code == SMP_FATAL_SHUTDOWN_RESPONSE); + } + + _SMP_barrier_Wait(&barrier, &barrier_state, cpu_count); if (self == main_cpu) { uint32_t cpu; - for (cpu = 0; cpu < MAX_CPUS; ++cpu) { + for (cpu = 0; cpu < cpu_count; ++cpu) { const Per_CPU_Control *per_cpu = _Per_CPU_Get_by_index( cpu ); Per_CPU_State state = _Per_CPU_Get_state(per_cpu); assert(state == PER_CPU_STATE_SHUTDOWN); } + for (cpu = cpu_count; cpu < MAX_CPUS; ++cpu) { + const Per_CPU_Control *per_cpu = _Per_CPU_Get_by_index( cpu ); + Per_CPU_State state = _Per_CPU_Get_state(per_cpu); + + assert(state == PER_CPU_STATE_INITIAL); + } + TEST_END(); + } else { + _SMP_barrier_Wait(&barrier, &barrier_state, cpu_count); } } +} - _SMP_barrier_Wait( - &barrier, - &barrier_state, - rtems_scheduler_get_processor_maximum() - ); +static void shutdown_handler(void *arg) +{ + _SMP_Request_shutdown(); + _SMP_Fatal(SMP_FATAL_SHUTDOWN); } +static const Per_CPU_Job_context shutdown_context = { + .handler = shutdown_handler +}; + +static Per_CPU_Job shutdown_job = { + .context = &shutdown_context +}; + static rtems_status_code test_driver_init( rtems_device_major_number major, rtems_device_minor_number minor, @@ -89,6 +115,7 @@ static rtems_status_code test_driver_init( assert(rtems_configuration_get_maximum_processors() == MAX_CPUS); main_cpu = self; + other_cpu = (self + 1) % cpu_count; for (cpu = 0; cpu < MAX_CPUS; ++cpu) { const Per_CPU_Control *per_cpu = _Per_CPU_Get_by_index( cpu ); @@ -107,10 +134,14 @@ static rtems_status_code test_driver_init( } if (cpu_count > 1) { - uint32_t other = (self + 1) % cpu_count; - Per_CPU_Control *per_cpu = _Per_CPU_Get_by_index( other ); - - _Per_CPU_Set_state(per_cpu, PER_CPU_STATE_SHUTDOWN); + Per_CPU_Control *per_cpu = _Per_CPU_Get_by_index( other_cpu ); + + _Per_CPU_Add_job(per_cpu, &shutdown_job); + _Atomic_Fetch_or_ulong( + &per_cpu->message, + SMP_MESSAGE_PERFORM_JOBS, + ATOMIC_ORDER_RELEASE + ); } else { TEST_END(); exit(0); diff --git a/testsuites/smptests/smpfatal01/smpfatal01.doc b/testsuites/smptests/smpfatal01/smpfatal01.doc index c037cfe78b..c6b54b7dd1 100644 --- a/testsuites/smptests/smpfatal01/smpfatal01.doc +++ b/testsuites/smptests/smpfatal01/smpfatal01.doc @@ -4,7 +4,8 @@ test set name: smpfatal01 directives: - - _Per_CPU_State_change() + - _SMP_Request_shutdown() + - _SMP_Request_start_multitasking() concepts: diff --git a/testsuites/smptests/smpfatal02/init.c b/testsuites/smptests/smpfatal02/init.c index 25321ca27b..5528a4315d 100644 --- a/testsuites/smptests/smpfatal02/init.c +++ b/testsuites/smptests/smpfatal02/init.c @@ -47,6 +47,7 @@ static void fatal_extension( { SMP_barrier_State barrier_state = SMP_BARRIER_STATE_INITIALIZER; uint32_t self = rtems_scheduler_get_processor(); + uint32_t cpu_count = rtems_scheduler_get_processor_maximum(); assert(!always_set_to_false); @@ -57,25 +58,29 @@ static void fatal_extension( assert(code == 0xdeadbeef); _SMP_Request_shutdown(); + _SMP_barrier_Wait(&barrier, &barrier_state, cpu_count); - for (cpu = 0; cpu < MAX_CPUS; ++cpu) { + for (cpu = 0; cpu < cpu_count; ++cpu) { const Per_CPU_Control *per_cpu = _Per_CPU_Get_by_index( cpu ); Per_CPU_State state = _Per_CPU_Get_state(per_cpu); assert(state == PER_CPU_STATE_SHUTDOWN); } + for (cpu = cpu_count; cpu < MAX_CPUS; ++cpu) { + const Per_CPU_Control *per_cpu = _Per_CPU_Get_by_index( cpu ); + Per_CPU_State state = _Per_CPU_Get_state(per_cpu); + + assert(state == PER_CPU_STATE_INITIAL); + } + TEST_END(); } else if ( source == RTEMS_FATAL_SOURCE_SMP ) { assert(self != main_cpu); - assert(code == SMP_FATAL_SHUTDOWN); + assert(code == SMP_FATAL_SHUTDOWN_RESPONSE); + _SMP_barrier_Wait(&barrier, &barrier_state, cpu_count); + _SMP_barrier_Wait(&barrier, &barrier_state, cpu_count); } - - _SMP_barrier_Wait( - &barrier, - &barrier_state, - rtems_scheduler_get_processor_maximum() - ); } static rtems_status_code test_driver_init( diff --git a/testsuites/smptests/smpfatal02/smpfatal02.doc b/testsuites/smptests/smpfatal02/smpfatal02.doc index 9e2e002b37..b962f528ad 100644 --- a/testsuites/smptests/smpfatal02/smpfatal02.doc +++ b/testsuites/smptests/smpfatal02/smpfatal02.doc @@ -4,7 +4,8 @@ test set name: smpfatal02 directives: - - _Per_CPU_State_change() + - _Terminate() + - _SMP_Start_multitasking_on_secondary_processor() concepts: -- 2.26.2 _______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel