[PATCH 2/4] score: Simplify SMP processor state handling

Gedare Bloom gedare at rtems.org
Wed Jul 28 16:17:20 UTC 2021


On Wed, Jul 28, 2021 at 5:18 AM Sebastian Huber
<sebastian.huber at embedded-brains.de> wrote:
>
> 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.
member

> + * The current state of a processor can be get by _Per_CPU_Get_state().  Only
s/get/gotten or some other word here.

> + * 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
> +
This is overlapping with SMP_MESSAGE_SHUTDOWN is that purposeful and safe to do?

>  /**
>   * @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
s/if/for    ?

> + *   the message.
> + */
> +void _SMP_Try_to_process_message(
> +  Per_CPU_Control *cpu_self,
> +  unsigned long    message
> +);
> +
>  /**
>   * @brief Interrupts handler for inter-processor interrupts.
s/Interrupts/Interrupt

>   *
> - * @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.
delete 'the'

>   */
>
>  /*
> @@ -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,
Should this constant be defined for some kind of meaningful term?

> +    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 at rtems.org
> http://lists.rtems.org/mailman/listinfo/devel


More information about the devel mailing list