[PATCH v2] score: SMP initialization and shutdown changes

Sebastian Huber sebastian.huber at embedded-brains.de
Thu Feb 20 16:22:07 UTC 2014


Rename _SMP_Request_other_cores_to_perform_first_context_switch() into
_SMP_Request_start_multitasking() since this requests now a multitasking
start on all configured and available processors.  The name corresponds
_Thread_Start_multitasking() and
_SMP_Start_multitasking_on_secondary_processor() actions issued in
response to this request.  Move in source file to right place.

Rename PER_CPU_STATE_READY_TO_BEGIN_MULTITASKING into
PER_CPU_STATE_READY_TO_START_MULTITASKING.

Rename PER_CPU_STATE_BEGIN_MULTITASKING into
PER_CPU_STATE_REQUEST_START_MULTITASKING.

Rename _SMP_Request_other_cores_to_shutdown() into
_SMP_Request_shutdown().

Add a per-CPU state lock to protect all changes.  This was necessary to
offer a controlled shutdown of the system (atomic read/writes alone are
not sufficient for this kind of synchronization).

Add documentation for Per_CPU_State.

Delete debug output.

New tests smptests/smpfatal01 and smptests/smpfatal02.
---
 cpukit/sapi/src/exinit.c                      |    2 +-
 cpukit/score/include/rtems/score/percpu.h     |   82 ++++++++------
 cpukit/score/include/rtems/score/smpimpl.h    |   22 ++--
 cpukit/score/src/interr.c                     |    2 +-
 cpukit/score/src/percpu.c                     |  158 ++++++++++++++++++++++--
 cpukit/score/src/smp.c                        |   77 ++++---------
 cpukit/score/src/threadstartmultitasking.c    |    2 +-
 testsuites/smptests/Makefile.am               |    2 +
 testsuites/smptests/configure.ac              |    2 +
 testsuites/smptests/smpfatal01/Makefile.am    |   19 +++
 testsuites/smptests/smpfatal01/init.c         |  130 ++++++++++++++++++++
 testsuites/smptests/smpfatal01/smpfatal01.doc |   12 ++
 testsuites/smptests/smpfatal01/smpfatal01.scn |    2 +
 testsuites/smptests/smpfatal02/Makefile.am    |   19 +++
 testsuites/smptests/smpfatal02/init.c         |  135 +++++++++++++++++++++
 testsuites/smptests/smpfatal02/smpfatal02.doc |   12 ++
 testsuites/smptests/smpfatal02/smpfatal02.scn |    2 +
 17 files changed, 563 insertions(+), 117 deletions(-)
 create mode 100644 testsuites/smptests/smpfatal01/Makefile.am
 create mode 100644 testsuites/smptests/smpfatal01/init.c
 create mode 100644 testsuites/smptests/smpfatal01/smpfatal01.doc
 create mode 100644 testsuites/smptests/smpfatal01/smpfatal01.scn
 create mode 100644 testsuites/smptests/smpfatal02/Makefile.am
 create mode 100644 testsuites/smptests/smpfatal02/init.c
 create mode 100644 testsuites/smptests/smpfatal02/smpfatal02.doc
 create mode 100644 testsuites/smptests/smpfatal02/smpfatal02.scn

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




More information about the devel mailing list