[rtems commit] score: Add clustered/partitioned scheduling

Sebastian Huber sebh at rtems.org
Tue Apr 15 09:08:30 UTC 2014


Module:    rtems
Branch:    master
Commit:    c5831a3f9af11228dbdaabaf01f69d37e55684ef
Changeset: http://git.rtems.org/rtems/commit/?id=c5831a3f9af11228dbdaabaf01f69d37e55684ef

Author:    Sebastian Huber <sebastian.huber at embedded-brains.de>
Date:      Wed Apr  9 15:07:54 2014 +0200

score: Add clustered/partitioned scheduling

Clustered/partitioned scheduling helps to control the worst-case
latencies in the system.  The goal is to reduce the amount of shared
state in the system and thus prevention of lock contention.  Modern
multi-processor systems tend to have several layers of data and
instruction caches.  With clustered/partitioned scheduling it is
possible to honour the cache topology of a system and thus avoid
expensive cache synchronization traffic.

We have clustered scheduling in case the set of processors of a system
is partitioned into non-empty pairwise-disjoint subsets.  These subsets
are called clusters.  Clusters with a cardinality of one are partitions.
Each cluster is owned by exactly one scheduler instance.

---

 c/src/lib/libbsp/i386/shared/smp/smp-imps.c        |    8 +-
 cpukit/posix/src/pthreadcreate.c                   |    7 +-
 cpukit/posix/src/pthreadsetaffinitynp.c            |    1 -
 cpukit/rtems/src/clocktick.c                       |    2 +-
 cpukit/rtems/src/taskcreate.c                      |    2 +
 cpukit/rtems/src/tasksetaffinity.c                 |    1 -
 cpukit/sapi/include/confdefs.h                     |  113 ++++++++++
 cpukit/sapi/include/rtems/scheduler.h              |   23 ++
 cpukit/score/include/rtems/score/percpu.h          |   19 ++
 cpukit/score/include/rtems/score/scheduler.h       |   64 ++++++-
 cpukit/score/include/rtems/score/schedulerimpl.h   |  176 ++++++++++++----
 cpukit/score/include/rtems/score/smpimpl.h         |    9 +
 cpukit/score/include/rtems/score/thread.h          |   14 +-
 cpukit/score/include/rtems/score/threadimpl.h      |    1 +
 cpukit/score/src/percpu.c                          |    3 +-
 cpukit/score/src/schedulerdefaulttick.c            |   14 +--
 cpukit/score/src/schedulersetaffinity.c            |   31 ++-
 cpukit/score/src/smp.c                             |   79 ++++++--
 cpukit/score/src/threadcreateidle.c                |    6 +-
 cpukit/score/src/threadinitialize.c                |    4 +-
 cpukit/score/src/threadstart.c                     |    8 +-
 doc/user/conf.t                                    |  207 +++++++++++++++++--
 testsuites/smptests/Makefile.am                    |    9 +-
 testsuites/smptests/configure.ac                   |    8 +-
 testsuites/smptests/smpfatal04/Makefile.am         |   19 ++
 testsuites/smptests/smpfatal04/init.c              |   71 +++++++
 testsuites/smptests/smpfatal04/smpfatal04.doc      |   11 +
 testsuites/smptests/smpfatal04/smpfatal04.scn      |    2 +
 testsuites/smptests/smpfatal05/Makefile.am         |   19 ++
 testsuites/smptests/smpfatal05/init.c              |   90 ++++++++
 testsuites/smptests/smpfatal05/smpfatal05.doc      |   11 +
 testsuites/smptests/smpfatal05/smpfatal05.scn      |    2 +
 testsuites/smptests/smpfatal06/Makefile.am         |   19 ++
 testsuites/smptests/smpfatal06/init.c              |   81 +++++++
 testsuites/smptests/smpfatal06/smpfatal06.doc      |   11 +
 testsuites/smptests/smpfatal06/smpfatal06.scn      |    2 +
 testsuites/smptests/smpfatal07/Makefile.am         |   19 ++
 testsuites/smptests/smpfatal07/init.c              |   75 +++++++
 testsuites/smptests/smpfatal07/smpfatal07.doc      |   12 +
 testsuites/smptests/smpfatal07/smpfatal07.scn      |    2 +
 testsuites/smptests/smpfatal08/Makefile.am         |   19 ++
 testsuites/smptests/smpfatal08/init.c              |  132 ++++++++++++
 testsuites/smptests/smpfatal08/smpfatal08.doc      |   11 +
 testsuites/smptests/smpfatal08/smpfatal08.scn      |    2 +
 testsuites/smptests/smpscheduler02/Makefile.am     |   19 ++
 testsuites/smptests/smpscheduler02/init.c          |  222 ++++++++++++++++++++
 .../smptests/smpscheduler02/smpscheduler02.doc     |   12 +
 .../smptests/smpscheduler02/smpscheduler02.scn     |    2 +
 testsuites/sptests/spscheduler01/init.c            |   29 ++-
 49 files changed, 1589 insertions(+), 114 deletions(-)

diff --git a/c/src/lib/libbsp/i386/shared/smp/smp-imps.c b/c/src/lib/libbsp/i386/shared/smp/smp-imps.c
index 19b23e2..fdbf915 100644
--- a/c/src/lib/libbsp/i386/shared/smp/smp-imps.c
+++ b/c/src/lib/libbsp/i386/shared/smp/smp-imps.c
@@ -57,6 +57,7 @@
 #include <bsp/smp-imps.h>
 #include <bsp/irq.h>
 #include <rtems/score/smpimpl.h>
+#include <rtems/score/schedulerimpl.h>
 
 /*
  *  XXXXX  The following absolutely must be defined!!!
@@ -386,7 +387,12 @@ imps_read_config_table(unsigned start, int count)
     switch (*((unsigned char *)start)) {
     case IMPS_BCT_PROCESSOR:
       if ( imps_num_cpus < rtems_configuration_get_maximum_processors() ) {
-	add_processor((imps_processor *)start);
+        const Scheduler_Assignment *assignment =
+          _Scheduler_Get_assignment((uint32_t) imps_num_cpus);
+
+        if (_Scheduler_Should_start_processor(assignment)) {
+          add_processor((imps_processor *)start);
+        }
       } else
         imps_num_cpus++;
       start += 12;  /* 20 total */
diff --git a/cpukit/posix/src/pthreadcreate.c b/cpukit/posix/src/pthreadcreate.c
index f85e1ef..c448c42 100644
--- a/cpukit/posix/src/pthreadcreate.c
+++ b/cpukit/posix/src/pthreadcreate.c
@@ -60,6 +60,7 @@ int pthread_create(
   bool                                is_fp;
   bool                                status;
   Thread_Control                     *the_thread;
+  Thread_Control                     *executing;
   POSIX_API_Control                  *api;
   int                                 schedpolicy = SCHED_RR;
   struct sched_param                  schedparam;
@@ -89,6 +90,8 @@ int pthread_create(
     rtems_set_errno_and_return_minus_one( ENOSYS );
   #endif
 
+  executing = _Thread_Get_executing();
+
   /*
    *  P1003.1c/Draft 10, p. 121.
    *
@@ -99,7 +102,7 @@ int pthread_create(
    */
   switch ( the_attr->inheritsched ) {
     case PTHREAD_INHERIT_SCHED:
-      api = _Thread_Get_executing()->API_Extensions[ THREAD_API_POSIX ];
+      api = executing->API_Extensions[ THREAD_API_POSIX ];
       schedpolicy = api->schedpolicy;
       schedparam  = api->schedparam;
       break;
@@ -176,6 +179,7 @@ int pthread_create(
   status = _Thread_Initialize(
     &_POSIX_Threads_Information,
     the_thread,
+    _Scheduler_Get( executing ),
     the_attr->stackaddr,
     _POSIX_Threads_Ensure_minimum_stack(the_attr->stacksize),
     is_fp,
@@ -194,7 +198,6 @@ int pthread_create(
 
 #if defined(RTEMS_SMP) && __RTEMS_HAVE_SYS_CPUSET_H__
    status = _Scheduler_Set_affinity(
-     _Scheduler_Get( the_thread ),
      the_thread,
      the_attr->affinitysetsize,
      the_attr->affinityset
diff --git a/cpukit/posix/src/pthreadsetaffinitynp.c b/cpukit/posix/src/pthreadsetaffinitynp.c
index d9df75b..711d6dc 100644
--- a/cpukit/posix/src/pthreadsetaffinitynp.c
+++ b/cpukit/posix/src/pthreadsetaffinitynp.c
@@ -48,7 +48,6 @@ int pthread_setaffinity_np(
 
     case OBJECTS_LOCAL:
       ok = _Scheduler_Set_affinity(
-        _Scheduler_Get( the_thread ),
         the_thread,
         cpusetsize,
         cpuset
diff --git a/cpukit/rtems/src/clocktick.c b/cpukit/rtems/src/clocktick.c
index 1abaa7f..a026b44 100644
--- a/cpukit/rtems/src/clocktick.c
+++ b/cpukit/rtems/src/clocktick.c
@@ -34,7 +34,7 @@ rtems_status_code rtems_clock_tick( void )
 
   _Watchdog_Tickle_ticks();
 
-  _Scheduler_Tick( _Scheduler_Get( NULL ) );
+  _Scheduler_Tick();
 
 #if defined( RTEMS_SMP )
   _Thread_Enable_dispatch();
diff --git a/cpukit/rtems/src/taskcreate.c b/cpukit/rtems/src/taskcreate.c
index 35dd37c..65a8d33 100644
--- a/cpukit/rtems/src/taskcreate.c
+++ b/cpukit/rtems/src/taskcreate.c
@@ -23,6 +23,7 @@
 #include <rtems/rtems/modesimpl.h>
 #include <rtems/rtems/support.h>
 #include <rtems/score/apimutex.h>
+#include <rtems/score/schedulerimpl.h>
 #include <rtems/score/sysstate.h>
 #include <rtems/score/threadimpl.h>
 
@@ -140,6 +141,7 @@ rtems_status_code rtems_task_create(
   status = _Thread_Initialize(
     &_RTEMS_tasks_Information,
     the_thread,
+    _Scheduler_Get_by_CPU_index( _SMP_Get_current_processor() ),
     NULL,
     stack_size,
     is_fp,
diff --git a/cpukit/rtems/src/tasksetaffinity.c b/cpukit/rtems/src/tasksetaffinity.c
index 6d8def7..3294f97 100644
--- a/cpukit/rtems/src/tasksetaffinity.c
+++ b/cpukit/rtems/src/tasksetaffinity.c
@@ -43,7 +43,6 @@ rtems_status_code rtems_task_set_affinity(
 
     case OBJECTS_LOCAL:
       ok = _Scheduler_Set_affinity(
-        _Scheduler_Get( the_thread ),
         the_thread,
         cpusetsize,
         cpuset
diff --git a/cpukit/sapi/include/confdefs.h b/cpukit/sapi/include/confdefs.h
index 5ec0cf2..c8a9d0e 100644
--- a/cpukit/sapi/include/confdefs.h
+++ b/cpukit/sapi/include/confdefs.h
@@ -820,6 +820,119 @@ const rtems_libio_helper rtems_fs_init_helper =
   #if defined(RTEMS_SMP)
     const size_t _Scheduler_Count =
       RTEMS_ARRAY_SIZE( _Scheduler_Table );
+
+    const Scheduler_Assignment _Scheduler_Assignments[] = {
+      #if defined(CONFIGURE_SMP_SCHEDULER_ASSIGNMENTS)
+        CONFIGURE_SMP_SCHEDULER_ASSIGNMENTS
+      #else
+        #define CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT \
+          RTEMS_SCHEDULER_ASSIGN( \
+            0, \
+            RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL \
+          )
+        CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
+        #if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 2
+          , CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
+        #endif
+        #if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 3
+          , CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
+        #endif
+        #if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 4
+          , CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
+        #endif
+        #if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 5
+          , CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
+        #endif
+        #if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 6
+          , CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
+        #endif
+        #if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 7
+          , CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
+        #endif
+        #if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 8
+          , CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
+        #endif
+        #if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 9
+          , CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
+        #endif
+        #if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 10
+          , CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
+        #endif
+        #if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 11
+          , CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
+        #endif
+        #if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 12
+          , CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
+        #endif
+        #if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 13
+          , CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
+        #endif
+        #if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 14
+          , CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
+        #endif
+        #if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 15
+          , CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
+        #endif
+        #if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 16
+          , CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
+        #endif
+        #if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 17
+          , CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
+        #endif
+        #if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 18
+          , CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
+        #endif
+        #if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 19
+          , CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
+        #endif
+        #if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 20
+          , CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
+        #endif
+        #if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 21
+          , CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
+        #endif
+        #if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 22
+          , CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
+        #endif
+        #if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 23
+          , CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
+        #endif
+        #if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 24
+          , CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
+        #endif
+        #if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 25
+          , CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
+        #endif
+        #if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 26
+          , CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
+        #endif
+        #if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 27
+          , CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
+        #endif
+        #if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 28
+          , CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
+        #endif
+        #if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 29
+          , CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
+        #endif
+        #if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 30
+          , CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
+        #endif
+        #if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 31
+          , CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
+        #endif
+        #if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 32
+          , CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
+        #endif
+        #undef CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
+      #endif
+    };
+
+    RTEMS_STATIC_ASSERT(
+      CONFIGURE_SMP_MAXIMUM_PROCESSORS
+        == RTEMS_ARRAY_SIZE( _Scheduler_Assignments ),
+      _Scheduler_Assignments
+    );
   #endif
 
   #if defined(CONFIGURE_SCHEDULER_EDF)
diff --git a/cpukit/sapi/include/rtems/scheduler.h b/cpukit/sapi/include/rtems/scheduler.h
index 06824e9..ce54559 100644
--- a/cpukit/sapi/include/rtems/scheduler.h
+++ b/cpukit/sapi/include/rtems/scheduler.h
@@ -26,6 +26,29 @@
 #define RTEMS_SCHEDULER_CONTEXT_NAME( name ) \
   _Configuration_Scheduler_ ## name
 
+#if defined(RTEMS_SMP)
+  /* This object doesn't exist and indicates a configuration error */
+  extern const Scheduler_Control RTEMS_SCHEDULER_INVALID_INDEX;
+
+  #define RTEMS_SCHEDULER_ASSIGN_DEFAULT \
+    SCHEDULER_ASSIGN_DEFAULT
+
+  #define RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL \
+    SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL
+
+  #define RTEMS_SCHEDULER_ASSIGN_PROCESSOR_MANDATORY \
+    SCHEDULER_ASSIGN_PROCESSOR_MANDATORY
+
+  #define RTEMS_SCHEDULER_ASSIGN( index, attr ) \
+    { \
+      ( index ) < RTEMS_ARRAY_SIZE( _Scheduler_Table ) ? \
+        &_Scheduler_Table[ ( index ) ] : &RTEMS_SCHEDULER_INVALID_INDEX, \
+      ( attr ) \
+    }
+
+  #define RTEMS_SCHEDULER_ASSIGN_NO_SCHEDULER { NULL, 0 }
+#endif
+
 /*
  * This file should be only included in the context of <rtems/confdefs.h>.
  * Define the scheduler configuration macros only in case the corresponding
diff --git a/cpukit/score/include/rtems/score/percpu.h b/cpukit/score/include/rtems/score/percpu.h
index 9a6b169..e491ffa 100644
--- a/cpukit/score/include/rtems/score/percpu.h
+++ b/cpukit/score/include/rtems/score/percpu.h
@@ -316,6 +316,12 @@ typedef struct {
      * @see _Per_CPU_State_change().
      */
     Per_CPU_State state;
+
+    /**
+     * @brief Indicates if the processor has been successfully started via
+     * _CPU_SMP_Start_processor().
+     */
+    bool started;
   #endif
 
   Per_CPU_Stats Stats;
@@ -462,6 +468,19 @@ static inline uint32_t _Per_CPU_Get_index( const Per_CPU_Control *per_cpu )
   return ( uint32_t ) ( per_cpu_envelope - &_Per_CPU_Information[ 0 ] );
 }
 
+static inline bool _Per_CPU_Is_processor_started(
+  const Per_CPU_Control *per_cpu
+)
+{
+#if defined( RTEMS_SMP )
+  return per_cpu->started;
+#else
+  (void) per_cpu;
+
+  return true;
+#endif
+}
+
 #if defined( RTEMS_SMP )
 
 static inline void _Per_CPU_Send_interrupt( const Per_CPU_Control *per_cpu )
diff --git a/cpukit/score/include/rtems/score/scheduler.h b/cpukit/score/include/rtems/score/scheduler.h
index 3fd47c7..9002ef8 100644
--- a/cpukit/score/include/rtems/score/scheduler.h
+++ b/cpukit/score/include/rtems/score/scheduler.h
@@ -102,7 +102,7 @@ typedef struct {
   );
 
   /** perform scheduler update actions required at each clock tick */
-  void ( *tick )( const Scheduler_Control * );
+  void ( *tick )( const Scheduler_Control *, Thread_Control * );
 
   /**
    * @brief Starts the idle thread for a particular processor.
@@ -149,7 +149,12 @@ typedef struct {
  * this structure at the begin of its context structure.
  */
 typedef struct {
-  /* No fields yet */
+#if defined(RTEMS_SMP)
+  /**
+   * @brief Count of processors owned by this scheduler instance.
+   */
+  uint32_t processor_count;
+#endif
 } Scheduler_Context;
 
 /**
@@ -198,6 +203,55 @@ extern const Scheduler_Control _Scheduler_Table[];
   #define _Scheduler_Count ( (size_t) 1 )
 #endif
 
+#if defined(RTEMS_SMP)
+  /**
+   * @brief The scheduler assignment default attributes.
+   */
+  #define SCHEDULER_ASSIGN_DEFAULT UINT32_C(0x0)
+
+  /**
+   * @brief The presence of this processor is optional.
+   */
+  #define SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL SCHEDULER_ASSIGN_DEFAULT
+
+  /**
+   * @brief The presence of this processor is mandatory.
+   */
+  #define SCHEDULER_ASSIGN_PROCESSOR_MANDATORY UINT32_C(0x1)
+
+  /**
+   * @brief Scheduler assignment.
+   */
+  typedef struct {
+    /**
+     * @brief The scheduler for this processor.
+     */
+    const Scheduler_Control *scheduler;
+
+    /**
+     * @brief The scheduler assignment attributes.
+     *
+     * Use @ref SCHEDULER_ASSIGN_DEFAULT to select default attributes.
+     *
+     * The presence of a processor can be
+     * - @ref SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL, or
+     * - @ref SCHEDULER_ASSIGN_PROCESSOR_MANDATORY.
+     */
+    uint32_t attributes;
+  } Scheduler_Assignment;
+
+  /**
+   * @brief The scheduler assignments.
+   *
+   * The length of this array must be equal to the maximum processors.
+   *
+   * Application provided via <rtems/confdefs.h>.
+   *
+   * @see _Scheduler_Table and rtems_configuration_get_maximum_processors().
+   */
+  extern const Scheduler_Assignment _Scheduler_Assignments[];
+#endif
+
 /**
  * @brief Returns an arbitrary non-NULL value.
  *
@@ -253,8 +307,12 @@ void _Scheduler_default_Release_job(
  * This routine is invoked as part of processing each clock tick.
  *
  * @param[in] scheduler The scheduler.
+ * @param[in] execution An executing thread.
  */
-void _Scheduler_default_Tick( const Scheduler_Control *scheduler );
+void _Scheduler_default_Tick(
+  const Scheduler_Control *scheduler,
+  Thread_Control          *executing
+);
 
 /**
  * @brief Starts an idle thread.
diff --git a/cpukit/score/include/rtems/score/schedulerimpl.h b/cpukit/score/include/rtems/score/schedulerimpl.h
index 8b80db7..35054df 100644
--- a/cpukit/score/include/rtems/score/schedulerimpl.h
+++ b/cpukit/score/include/rtems/score/schedulerimpl.h
@@ -21,6 +21,7 @@
 
 #include <rtems/score/scheduler.h>
 #include <rtems/score/cpusetimpl.h>
+#include <rtems/score/smpimpl.h>
 #include <rtems/score/threadimpl.h>
 
 #ifdef __cplusplus
@@ -41,6 +42,28 @@ extern "C" {
  */
 void _Scheduler_Handler_initialization( void );
 
+RTEMS_INLINE_ROUTINE const Scheduler_Control *_Scheduler_Get_by_CPU_index(
+  uint32_t cpu_index
+)
+{
+#if defined(RTEMS_SMP)
+  return _Scheduler_Assignments[ cpu_index ].scheduler;
+#else
+  (void) cpu_index;
+
+  return &_Scheduler_Table[ 0 ];
+#endif
+}
+
+RTEMS_INLINE_ROUTINE const Scheduler_Control *_Scheduler_Get_by_CPU(
+  const Per_CPU_Control *cpu
+)
+{
+  uint32_t cpu_index = _Per_CPU_Get_index( cpu );
+
+  return _Scheduler_Get_by_CPU_index( cpu_index );
+}
+
 /**
  * The preferred method to add a new scheduler is to define the jump table
  * entries and add a case to the _Scheduler_Initialize routine.
@@ -234,11 +257,19 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Release_job(
  * scheduler which support standard RTEMS features, this includes
  * time-slicing management.
  */
-RTEMS_INLINE_ROUTINE void _Scheduler_Tick(
-  const Scheduler_Control *scheduler
-)
+RTEMS_INLINE_ROUTINE void _Scheduler_Tick( void )
 {
-  ( *scheduler->Operations.tick )( scheduler );
+  uint32_t cpu_count = _SMP_Get_processor_count();
+  uint32_t cpu_index;
+
+  for ( cpu_index = 0 ; cpu_index < cpu_count ; ++cpu_index ) {
+    const Per_CPU_Control *cpu = _Per_CPU_Get_by_index( cpu_index );
+    const Scheduler_Control *scheduler = _Scheduler_Get_by_CPU( cpu );
+
+    if ( scheduler != NULL ) {
+      ( *scheduler->Operations.tick )( scheduler, cpu->executing );
+    }
+  }
 }
 
 /**
@@ -258,6 +289,47 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Start_idle(
   ( *scheduler->Operations.start_idle )( scheduler, the_thread, cpu );
 }
 
+#if defined(RTEMS_SMP)
+RTEMS_INLINE_ROUTINE const Scheduler_Assignment *_Scheduler_Get_assignment(
+  uint32_t cpu_index
+)
+{
+  return &_Scheduler_Assignments[ cpu_index ];
+}
+
+RTEMS_INLINE_ROUTINE bool _Scheduler_Is_mandatory_processor(
+  const Scheduler_Assignment *assignment
+)
+{
+  return (assignment->attributes & SCHEDULER_ASSIGN_PROCESSOR_MANDATORY) != 0;
+}
+
+RTEMS_INLINE_ROUTINE bool _Scheduler_Should_start_processor(
+  const Scheduler_Assignment *assignment
+)
+{
+  return assignment->scheduler != NULL;
+}
+#endif /* defined(RTEMS_SMP) */
+
+RTEMS_INLINE_ROUTINE bool _Scheduler_Has_processor_ownership(
+  const Scheduler_Control *scheduler,
+  uint32_t cpu_index
+)
+{
+#if defined(RTEMS_SMP)
+  const Scheduler_Assignment *assignment =
+    _Scheduler_Get_assignment( cpu_index );
+
+  return assignment->scheduler == scheduler;
+#else
+  (void) scheduler;
+  (void) cpu_index;
+
+  return true;
+#endif
+}
+
 #if defined(__RTEMS_HAVE_SYS_CPUSET_H__)
 
 RTEMS_INLINE_ROUTINE void _Scheduler_Get_processor_set(
@@ -269,12 +341,18 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Get_processor_set(
   uint32_t cpu_count = _SMP_Get_processor_count();
   uint32_t cpu_index;
 
-  (void) scheduler;
-
   CPU_ZERO_S( cpusetsize, cpuset );
 
   for ( cpu_index = 0 ; cpu_index < cpu_count ; ++cpu_index ) {
+#if defined(RTEMS_SMP)
+    if ( _Scheduler_Has_processor_ownership( scheduler, cpu_index ) ) {
+      CPU_SET_S( (int) cpu_index, cpusetsize, cpuset );
+    }
+#else
+    (void) scheduler;
+
     CPU_SET_S( (int) cpu_index, cpusetsize, cpuset );
+#endif
   }
 }
 
@@ -299,6 +377,44 @@ bool _Scheduler_Get_affinity(
   cpu_set_t               *cpuset
 );
 
+RTEMS_INLINE_ROUTINE const Scheduler_Control *_Scheduler_Get(
+  Thread_Control *the_thread
+)
+{
+#if defined(RTEMS_SMP)
+  return the_thread->scheduler;
+#else
+  (void) the_thread;
+
+  return &_Scheduler_Table[ 0 ];
+#endif
+}
+
+RTEMS_INLINE_ROUTINE bool _Scheduler_Set(
+  const Scheduler_Control *scheduler,
+  Thread_Control          *the_thread
+)
+{
+  bool ok;
+
+  if ( _States_Is_dormant( the_thread->current_state ) ) {
+#if defined(RTEMS_SMP)
+    _Scheduler_Free( _Scheduler_Get( the_thread ), the_thread );
+    the_thread->scheduler = scheduler;
+    _Scheduler_Allocate( scheduler, the_thread );
+    _Scheduler_Update( scheduler, the_thread );
+#else
+    (void) scheduler;
+#endif
+
+    ok = true;
+  } else {
+    ok = false;
+  }
+
+  return ok;
+}
+
 RTEMS_INLINE_ROUTINE bool _Scheduler_default_Set_affinity_body(
   const Scheduler_Control *scheduler,
   Thread_Control          *the_thread,
@@ -311,22 +427,35 @@ RTEMS_INLINE_ROUTINE bool _Scheduler_default_Set_affinity_body(
   uint32_t cpu_index;
   bool     ok = true;
 
-  (void) scheduler;
-  (void) the_thread;
-
   for ( cpu_index = 0 ; cpu_index < cpu_count ; ++cpu_index ) {
+#if defined(RTEMS_SMP)
+    const Scheduler_Control *scheduler_of_cpu =
+      _Scheduler_Get_by_CPU_index( cpu_index );
+
+    ok = ok
+      && ( ( CPU_ISSET_S( (int) cpu_index, cpusetsize, cpuset )
+          && scheduler == scheduler_of_cpu )
+        || ( !CPU_ISSET_S( (int) cpu_index, cpusetsize, cpuset )
+          && scheduler != scheduler_of_cpu ) );
+#else
+    (void) scheduler;
+
     ok = ok && CPU_ISSET_S( (int) cpu_index, cpusetsize, cpuset );
+#endif
   }
 
   for ( ; cpu_index < cpu_max ; ++cpu_index ) {
     ok = ok && !CPU_ISSET_S( (int) cpu_index, cpusetsize, cpuset );
   }
 
+  if ( ok ) {
+    ok = _Scheduler_Set( scheduler, the_thread );
+  }
+
   return ok;
 }
 
 bool _Scheduler_Set_affinity(
-  const Scheduler_Control *scheduler,
   Thread_Control          *the_thread,
   size_t                   cpusetsize,
   const cpu_set_t         *cpuset
@@ -442,33 +571,6 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Change_priority_if_higher(
   }
 }
 
-RTEMS_INLINE_ROUTINE const Scheduler_Control *_Scheduler_Get(
-  Thread_Control *the_thread
-)
-{
-  (void) the_thread;
-
-  return &_Scheduler_Table[ 0 ];
-}
-
-RTEMS_INLINE_ROUTINE bool _Scheduler_Set(
-  const Scheduler_Control *scheduler,
-  Thread_Control          *the_thread
-)
-{
-  bool ok;
-
-  (void) scheduler;
-
-  if ( _States_Is_dormant( the_thread->current_state ) ) {
-    ok = true;
-  } else {
-    ok = false;
-  }
-
-  return ok;
-}
-
 RTEMS_INLINE_ROUTINE Objects_Id _Scheduler_Build_id( uint32_t scheduler_index )
 {
   return _Objects_Build_id(
diff --git a/cpukit/score/include/rtems/score/smpimpl.h b/cpukit/score/include/rtems/score/smpimpl.h
index 3e80860..225da0f 100644
--- a/cpukit/score/include/rtems/score/smpimpl.h
+++ b/cpukit/score/include/rtems/score/smpimpl.h
@@ -49,9 +49,18 @@ extern "C" {
 typedef enum {
   SMP_FATAL_SHUTDOWN,
   SMP_FATAL_SHUTDOWN_EARLY,
+  SMP_FATAL_BOOT_PROCESSOR_NOT_ASSIGNED_TO_SCHEDULER,
+  SMP_FATAL_MANDATORY_PROCESSOR_NOT_PRESENT,
+  SMP_FATAL_MULTITASKING_START_ON_UNASSIGNED_PROCESSOR,
+  SMP_FATAL_SCHEDULER_WITHOUT_PROCESSORS,
   SMP_FATAL_START_OF_MANDATORY_PROCESSOR_FAILED
 } SMP_Fatal_code;
 
+static inline void _SMP_Fatal( SMP_Fatal_code code )
+{
+  _Terminate( RTEMS_FATAL_SOURCE_SMP, false, code );
+}
+
 /**
  *  @brief Initialize SMP Handler
  *
diff --git a/cpukit/score/include/rtems/score/thread.h b/cpukit/score/include/rtems/score/thread.h
index 77e105b..5215d6a 100644
--- a/cpukit/score/include/rtems/score/thread.h
+++ b/cpukit/score/include/rtems/score/thread.h
@@ -33,13 +33,12 @@
 #include <rtems/score/threadq.h>
 #include <rtems/score/watchdog.h>
 
-#ifdef RTEMS_SMP
-#if __RTEMS_HAVE_SYS_CPUSET_H__
-#include <sys/cpuset.h>
-#include <rtems/score/cpuset.h>
-#endif
+#if defined(RTEMS_SMP)
+  #include <rtems/score/cpuset.h>
 #endif
 
+struct Scheduler_Control;
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -517,6 +516,11 @@ struct Thread_Control_struct {
    * _Thread_Kill_zombies().
    */
   volatile bool                         is_executing;
+
+  /**
+   * @brief The scheduler of this thread.
+   */
+  const struct Scheduler_Control       *scheduler;
 #endif
 
 #if __RTEMS_ADA__
diff --git a/cpukit/score/include/rtems/score/threadimpl.h b/cpukit/score/include/rtems/score/threadimpl.h
index 41b90e3..4efc85d 100644
--- a/cpukit/score/include/rtems/score/threadimpl.h
+++ b/cpukit/score/include/rtems/score/threadimpl.h
@@ -141,6 +141,7 @@ void _Thread_Stack_Free(
 bool _Thread_Initialize(
   Objects_Information                  *information,
   Thread_Control                       *the_thread,
+  const struct Scheduler_Control       *scheduler,
   void                                 *stack_area,
   size_t                                stack_size,
   bool                                  is_fp,
diff --git a/cpukit/score/src/percpu.c b/cpukit/score/src/percpu.c
index cb9a470..c396ace 100644
--- a/cpukit/score/src/percpu.c
+++ b/cpukit/score/src/percpu.c
@@ -22,7 +22,6 @@
 #include <rtems/score/assert.h>
 #include <rtems/score/smpimpl.h>
 #include <rtems/config.h>
-#include <rtems/fatal.h>
 
 #if defined(RTEMS_SMP)
 
@@ -154,7 +153,7 @@ void _Per_CPU_State_change(
     next_state == PER_CPU_STATE_SHUTDOWN
       && new_state != PER_CPU_STATE_SHUTDOWN
   ) {
-    rtems_fatal( RTEMS_FATAL_SOURCE_SMP, SMP_FATAL_SHUTDOWN );
+    _SMP_Fatal( SMP_FATAL_SHUTDOWN );
   }
 }
 
diff --git a/cpukit/score/src/schedulerdefaulttick.c b/cpukit/score/src/schedulerdefaulttick.c
index 6e7ed37..98cd05e 100644
--- a/cpukit/score/src/schedulerdefaulttick.c
+++ b/cpukit/score/src/schedulerdefaulttick.c
@@ -24,7 +24,7 @@
 #include <rtems/score/smp.h>
 #include <rtems/config.h>
 
-static void _Scheduler_default_Tick_for_executing(
+void _Scheduler_default_Tick(
   const Scheduler_Control *scheduler,
   Thread_Control          *executing
 )
@@ -83,15 +83,3 @@ static void _Scheduler_default_Tick_for_executing(
     #endif
   }
 }
-
-void _Scheduler_default_Tick( const Scheduler_Control *scheduler )
-{
-  uint32_t processor_count = _SMP_Get_processor_count();
-  uint32_t processor;
-
-  for ( processor = 0 ; processor < processor_count ; ++processor ) {
-    const Per_CPU_Control *per_cpu = _Per_CPU_Get_by_index( processor );
-
-    _Scheduler_default_Tick_for_executing( scheduler, per_cpu->executing );
-  }
-}
diff --git a/cpukit/score/src/schedulersetaffinity.c b/cpukit/score/src/schedulersetaffinity.c
index 2416a19..a20888b 100644
--- a/cpukit/score/src/schedulersetaffinity.c
+++ b/cpukit/score/src/schedulersetaffinity.c
@@ -21,7 +21,6 @@
 #if defined(__RTEMS_HAVE_SYS_CPUSET_H__)
 
 bool _Scheduler_Set_affinity(
-  const Scheduler_Control *scheduler,
   Thread_Control          *the_thread,
   size_t                   cpusetsize,
   const cpu_set_t         *cpuset
@@ -31,15 +30,31 @@ bool _Scheduler_Set_affinity(
 
   if ( _CPU_set_Is_large_enough( cpusetsize ) ) {
 #if defined(RTEMS_SMP)
-    ok = ( *scheduler->Operations.set_affinity )(
-      scheduler,
-      the_thread,
-      cpusetsize,
-      cpuset
-    );
+    uint32_t cpu_count = _SMP_Get_processor_count();
+    uint32_t cpu_index;
+
+    ok = false;
+
+    for ( cpu_index = 0 ; cpu_index < cpu_count ; ++cpu_index ) {
+      if ( CPU_ISSET_S( (int) cpu_index, cpusetsize, cpuset ) ) {
+        const Scheduler_Control *scheduler_of_cpu =
+          _Scheduler_Get_by_CPU_index( cpu_index );
+
+        if ( scheduler_of_cpu != NULL ) {
+          ok = ( *scheduler_of_cpu->Operations.set_affinity )(
+            scheduler_of_cpu,
+            the_thread,
+            cpusetsize,
+            cpuset
+          );
+        }
+
+        break;
+      }
+    }
 #else
     ok = _Scheduler_default_Set_affinity_body(
-      scheduler,
+      _Scheduler_Get( the_thread ),
       the_thread,
       cpusetsize,
       cpuset
diff --git a/cpukit/score/src/smp.c b/cpukit/score/src/smp.c
index 08677d8..6df7207 100644
--- a/cpukit/score/src/smp.c
+++ b/cpukit/score/src/smp.c
@@ -20,14 +20,68 @@
 
 #include <rtems/score/smpimpl.h>
 #include <rtems/score/assert.h>
+#include <rtems/score/schedulerimpl.h>
 #include <rtems/score/threaddispatch.h>
 #include <rtems/score/threadimpl.h>
 #include <rtems/config.h>
 
+static void _SMP_Check_scheduler_configuration( void )
+{
+  size_t n = _Scheduler_Count;
+  size_t i;
+
+  for ( i = 0 ; i < n ; ++i ) {
+    const Scheduler_Control *scheduler = &_Scheduler_Table[ i ];
+
+    if ( scheduler->context->processor_count == 0 ) {
+      _SMP_Fatal( SMP_FATAL_SCHEDULER_WITHOUT_PROCESSORS );
+    }
+  }
+}
+
+static void _SMP_Start_processors( uint32_t cpu_count )
+{
+  uint32_t cpu_self = _SMP_Get_current_processor();
+  uint32_t cpu_index;
+
+
+  for ( cpu_index = 0 ; cpu_index < cpu_count; ++cpu_index ) {
+    const Scheduler_Assignment *assignment =
+      _Scheduler_Get_assignment( cpu_index );
+    Per_CPU_Control *per_cpu = _Per_CPU_Get_by_index( cpu_index );
+    bool started;
+
+    if ( cpu_index != cpu_self ) {
+      if ( _Scheduler_Should_start_processor( assignment ) ) {
+        started = _CPU_SMP_Start_processor( cpu_index );
+
+        if ( !started && _Scheduler_Is_mandatory_processor( assignment ) ) {
+          _SMP_Fatal( SMP_FATAL_START_OF_MANDATORY_PROCESSOR_FAILED );
+        }
+      } else {
+        started = false;
+      }
+    } else {
+      started = true;
+
+      if ( !_Scheduler_Should_start_processor( assignment ) ) {
+        _SMP_Fatal( SMP_FATAL_BOOT_PROCESSOR_NOT_ASSIGNED_TO_SCHEDULER );
+      }
+    }
+
+    per_cpu->started = started;
+
+    if ( started ) {
+      ++assignment->scheduler->context->processor_count;
+    }
+  }
+
+  _SMP_Check_scheduler_configuration();
+}
+
 void _SMP_Handler_initialize( void )
 {
   uint32_t cpu_max = rtems_configuration_get_maximum_processors();
-  uint32_t cpu_self;
   uint32_t cpu_count;
   uint32_t cpu_index;
 
@@ -45,22 +99,17 @@ void _SMP_Handler_initialize( void )
   cpu_count = cpu_count < cpu_max ? cpu_count : cpu_max;
   _SMP_Processor_count = cpu_count;
 
-  cpu_self = _SMP_Get_current_processor();
+  for ( cpu_index = cpu_count ; cpu_index < cpu_max; ++cpu_index ) {
+    const Scheduler_Assignment *assignment =
+      _Scheduler_Get_assignment( cpu_index );
 
-  for ( cpu_index = 0 ; cpu_index < cpu_count; ++cpu_index ) {
-    if ( cpu_index != cpu_self ) {
-      bool ok = _CPU_SMP_Start_processor( cpu_index );
-
-      if ( !ok ) {
-        _Terminate(
-          RTEMS_FATAL_SOURCE_SMP,
-          false,
-          SMP_FATAL_START_OF_MANDATORY_PROCESSOR_FAILED
-        );
-      }
+    if ( _Scheduler_Is_mandatory_processor( assignment ) ) {
+      _SMP_Fatal( SMP_FATAL_MANDATORY_PROCESSOR_NOT_PRESENT );
     }
   }
 
+  _SMP_Start_processors( cpu_count );
+
   _CPU_SMP_Finalize_initialization( cpu_count );
 }
 
@@ -83,6 +132,10 @@ void _SMP_Start_multitasking_on_secondary_processor( void )
 {
   Per_CPU_Control *self_cpu = _Per_CPU_Get();
 
+  if ( !_Per_CPU_Is_processor_started( self_cpu ) ) {
+    _SMP_Fatal( SMP_FATAL_MULTITASKING_START_ON_UNASSIGNED_PROCESSOR );
+  }
+
   _Per_CPU_State_change( self_cpu, PER_CPU_STATE_READY_TO_START_MULTITASKING );
 
   _Thread_Start_multitasking();
diff --git a/cpukit/score/src/threadcreateidle.c b/cpukit/score/src/threadcreateidle.c
index e044b92..2a24265 100644
--- a/cpukit/score/src/threadcreateidle.c
+++ b/cpukit/score/src/threadcreateidle.c
@@ -19,6 +19,7 @@
 #endif
 
 #include <rtems/score/threadimpl.h>
+#include <rtems/score/schedulerimpl.h>
 #include <rtems/score/stackimpl.h>
 #include <rtems/config.h>
 
@@ -39,6 +40,7 @@ static void _Thread_Create_idle_for_cpu( Per_CPU_Control *per_cpu )
   _Thread_Initialize(
     &_Thread_Internal_information,
     idle,
+    _Scheduler_Get_by_CPU( per_cpu ),
     NULL,        /* allocate the stack */
     _Stack_Ensure_minimum( rtems_configuration_get_idle_task_stack_size() ),
     CPU_IDLE_TASK_IS_FP,
@@ -75,6 +77,8 @@ void _Thread_Create_idle( void )
   for ( processor = 0 ; processor < processor_count ; ++processor ) {
     Per_CPU_Control *per_cpu = _Per_CPU_Get_by_index( processor );
 
-    _Thread_Create_idle_for_cpu( per_cpu );
+    if ( _Per_CPU_Is_processor_started( per_cpu ) ) {
+      _Thread_Create_idle_for_cpu( per_cpu );
+    }
   }
 }
diff --git a/cpukit/score/src/threadinitialize.c b/cpukit/score/src/threadinitialize.c
index 153c1d0..f8e0e7d 100644
--- a/cpukit/score/src/threadinitialize.c
+++ b/cpukit/score/src/threadinitialize.c
@@ -31,6 +31,7 @@
 bool _Thread_Initialize(
   Objects_Information                  *information,
   Thread_Control                       *the_thread,
+  const Scheduler_Control              *scheduler,
   void                                 *stack_area,
   size_t                                stack_size,
   bool                                  is_fp,
@@ -50,7 +51,6 @@ bool _Thread_Initialize(
   bool                     extension_status;
   size_t                   i;
   bool                     scheduler_allocated = false;
-  const Scheduler_Control *scheduler;
 
   /*
    * Do not use _TLS_Size here since this will lead GCC to assume that this
@@ -188,6 +188,7 @@ bool _Thread_Initialize(
   the_thread->is_scheduled            = false;
   the_thread->is_in_the_air           = false;
   the_thread->is_executing            = false;
+  the_thread->scheduler               = scheduler;
 #endif
 
   /* Initialize the CPU for the non-SMP schedulers */
@@ -199,7 +200,6 @@ bool _Thread_Initialize(
   the_thread->real_priority           = priority;
   the_thread->Start.initial_priority  = priority;
 
-  scheduler = _Scheduler_Get( _Thread_Get_executing() );
   scheduler_allocated = _Scheduler_Allocate( scheduler, the_thread );
   if ( !scheduler_allocated ) {
     goto failed;
diff --git a/cpukit/score/src/threadstart.c b/cpukit/score/src/threadstart.c
index b65a2c3..dda9495 100644
--- a/cpukit/score/src/threadstart.c
+++ b/cpukit/score/src/threadstart.c
@@ -46,8 +46,12 @@ bool _Thread_Start(
     if ( cpu == NULL ) {
       _Thread_Ready( the_thread );
     } else {
-      the_thread->current_state = STATES_READY;
-      _Scheduler_Start_idle( _Scheduler_Get( the_thread ), the_thread, cpu );
+      const Scheduler_Control *scheduler = _Scheduler_Get_by_CPU( cpu );
+
+      if ( scheduler != NULL ) {
+        the_thread->current_state = STATES_READY;
+        _Scheduler_Start_idle( scheduler, the_thread, cpu );
+      }
     }
 
     _User_extensions_Thread_start( the_thread );
diff --git a/doc/user/conf.t b/doc/user/conf.t
index 9b093f8..a46e79b 100644
--- a/doc/user/conf.t
+++ b/doc/user/conf.t
@@ -3501,7 +3501,7 @@ configuration parameter is redundant.
 
 @subheading DESCRIPTION:
 The Deterministic Priority Scheduler is the default scheduler in RTEMS
-for single core applications and is designed for predictable performance
+for uni-processor applications and is designed for predictable performance
 under the highest loads.  It can block or unblock a thread in a constant
 amount of time.  This scheduler requires a variable amount of memory
 based upon the number of priorities configured in the system.
@@ -3572,7 +3572,7 @@ This is not defined by default.
 
 @subheading DESCRIPTION:
 The Earliest Deadline First Scheduler (EDF) is an alternative scheduler in
-RTEMS for single core applications. The EDF schedules tasks with dynamic
+RTEMS for uni-processor applications. The EDF schedules tasks with dynamic
 priorities equal to deadlines. The deadlines are declared using only
 Rate Monotonic manager which handles periodic behavior.  Period is always
 equal to deadline. If a task does not have any deadline declared or the
@@ -3612,7 +3612,7 @@ This is not defined by default.
 
 @subheading DESCRIPTION:
 The Constant Bandwidth Server Scheduler (CBS) is an alternative scheduler
-in RTEMS for single core applications. The CBS is a budget aware extension
+in RTEMS for uni-processor applications. The CBS is a budget aware extension
 of EDF scheduler. The goal of this scheduler is to ensure temporal
 isolation of tasks. The CBS is equipped with a set of additional rules
 and provides with an extensive API.
@@ -3685,14 +3685,14 @@ This is not defined by default.
 
 @subheading DESCRIPTION:
 The Simple SMP Priority Scheduler is derived from the Simple Priority
-Scheduler but is capable of scheduling threads across multiple cores.
+Scheduler but is capable of scheduling threads across multiple processors.
 It is designed to provide the same task scheduling behaviour as the
 Deterministic Priority Scheduler while distributing threads across
-multiple cores.  Being based upon the Simple Priority Scheduler, it also
+multiple processors.  Being based upon the Simple Priority Scheduler, it also
 maintains a single sorted list of all ready threads.  Thus blocking or
 unblocking a thread is not a constant time operation with this scheduler.
 
-In addition, when allocating threads to cores, the algorithm is not
+In addition, when allocating threads to processors, the algorithm is not
 constant time. This algorithm was not designed with efficiency as a
 primary design goal.  Its primary design goal was to provide an SMP-aware
 scheduling algorithm that is simple to understand.
@@ -3792,6 +3792,187 @@ guidance.  For guidance on the configuration macros, please examine
 Deterministic Priority Scheduler.
 
 @c
+ at c === Configuring Clustered/Partitioned Schedulers ===
+ at c
+ at subsection Configuring Clustered/Partitioned Schedulers
+
+Clustered/partitioned scheduling helps to control the worst-case latencies in
+the system.  The goal is to reduce the amount of shared state in the system and
+thus prevention of lock contention.  Modern multi-processor systems tend to
+have several layers of data and instruction caches.  With clustered/partitioned
+scheduling it is possible to honour the cache topology of a system and thus
+avoid expensive cache synchronization traffic.
+
+We have clustered scheduling in case the set of processors of a system is
+partitioned into non-empty pairwise-disjoint subsets.  These subsets are called
+clusters.  Clusters with a cardinality of one are partitions.  Each cluster is
+owned by exactly one scheduler instance.  In order to use clustered/partitioned
+scheduling the application designer has to answer two questions.
+
+ at enumerate
+ at item How is the set of processors partitioned into clusters/partitions?
+ at item Which scheduler is used for which cluster/partition?
+ at end enumerate
+
+ at subheading CONFIGURATION:
+
+The schedulers in an SMP system are statically configured on RTEMS.  Firstly
+the application must select which scheduling algorithms are available with the
+following defines
+
+ at itemize @bullet
+ at item @code{CONFIGURE_SCHEDULER_PRIORITY_SMP},
+ at item @code{CONFIGURE_SCHEDULER_SIMPLE_SMP}, and
+ at item @code{CONFIGURE_SCHEDULER_PRIORITY_AFFINITY_SMP}.
+ at end itemize
+
+This is necessary to calculate the per-thread overhead introduced by the
+schedulers.  After these definitions the configuration file must @code{#include
+<rtems/scheduler.h>} to have access to scheduler specific configuration macros.
+Each scheduler needs a context to store state information at run-time.  To
+provide a context for each scheduler is the next step.  Use the following
+macros to create scheduler contexts
+
+ at itemize @bullet
+ at item @code{RTEMS_SCHEDULER_CONTEXT_PRIORITY_SMP(name, prio_count)},
+ at item @code{RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(name)}, and
+ at item @code{RTEMS_SCHEDULER_CONTEXT_PRIORITY_AFFINITY_SMP(name, prio_count)}.
+ at end itemize
+
+The @code{name} parameter is used as part of a designator for a global
+variable, so the usual C/C++ designator rules apply.  Additional parameters are
+scheduler specific.  The schedulers are registered in the system via the
+scheduler table.  To create the scheduler table define
+ at code{CONFIGURE_SCHEDULER_CONTROLS} to a list of the following scheduler
+control initializers
+
+ at itemize @bullet
+ at item @code{RTEMS_SCHEDULER_CONTROL_PRIORITY_SMP(name, obj_name)},
+ at item @code{RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(name, obj_name)}, and
+ at item @code{RTEMS_SCHEDULER_CONTROL_PRIORITY_AFFINITY_SMP(name, obj_name)}.
+ at end itemize
+
+The @code{name} parameter must correspond to the parameter defining the
+scheduler context.  The @code{obj_name} determines the scheduler object name
+and can be used in @code{rtems_scheduler_ident()} to get the scheduler object
+identifier.
+
+The last step is to define which processor uses which scheduler.
+For this purpose a scheduler assignment table must be defined.  The entry count
+of this table must be equal to the configured maximum processors
+(@code{CONFIGURE_SMP_MAXIMUM_PROCESSORS}).  A processor assignment to a
+scheduler can be optional or mandatory.  The boot processor must have a
+scheduler assigned.  In case the system needs more mandatory processors than
+available then a fatal run-time error will occur.  To specify the scheduler
+assignments define @code{CONFIGURE_SMP_SCHEDULER_ASSIGNMENTS} to a list of
+ at code{RTEMS_SCHEDULER_ASSIGN(index, attr)} and
+ at code{RTEMS_SCHEDULER_ASSIGN_NO_SCHEDULER} macros.  The @code{index} parameter
+must be a valid index into the scheduler table.  The @code{attr} parameter
+defines the scheduler assignment attributes.  By default a scheduler assignment
+to a processor is optional.  For the scheduler assignment attribute use one of
+the mutually exclusive variants
+
+ at itemize @bullet
+ at item @code{RTEMS_SCHEDULER_ASSIGN_DEFAULT},
+ at item @code{RTEMS_SCHEDULER_ASSIGN_PROCESSOR_MANDATORY}, and
+ at item @code{RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL}.
+ at end itemize
+
+ at subheading ERRORS:
+
+In case one of the scheduler indices in
+ at code{CONFIGURE_SMP_SCHEDULER_ASSIGNMENTS} is invalid a link-time error will
+occur with an undefined reference to @code{RTEMS_SCHEDULER_INVALID_INDEX}.
+
+Some fatal errors may occur in case of scheduler configuration inconsistencies or a lack
+of processors on the system.  The fatal source is
+ at code{RTEMS_FATAL_SOURCE_SMP}.  None of the errors is internal.
+
+ at itemize @bullet
+ at item @code{SMP_FATAL_BOOT_PROCESSOR_NOT_ASSIGNED_TO_SCHEDULER} - the boot
+processor must have a scheduler assigned.
+ at item @code{SMP_FATAL_MANDATORY_PROCESSOR_NOT_PRESENT} - there exists a
+mandatory processor beyond the range of physically or virtually available
+processors.  The processor demand must be reduced for this system.
+ at item @code{SMP_FATAL_START_OF_MANDATORY_PROCESSOR_FAILED} - the start of a
+mandatory processor failed during system initialization.  The system may not
+have this processor at all or it could be a problem with a boot loader for
+example.
+the @code{CONFIGURE_SMP_SCHEDULER_ASSIGNMENTS} definition.
+ at item @code{SMP_FATAL_SCHEDULER_WITHOUT_PROCESSORS} - it is prohibited to have
+a scheduler managing the empty processor set.
+ at item @code{SMP_FATAL_MULTITASKING_START_ON_UNASSIGNED_PROCESSOR} - it is not
+allowed to start multitasking on a processor with no scheduler assigned.
+ at end itemize
+
+ at subheading EXAMPLE:
+
+The following example shows a scheduler configuration for a hypothetical
+product using two chip variants.  One variant has four processors which is used
+for the normal product line and another provides eight processors for the
+high-performance product line.  The first processor performs hard-real time
+control of actuators and sensors.  The second processor is not used by RTEMS at
+all and runs a Linux instance to provide a graphical user interface.  The
+additional processors are used for a worker thread pool to perform data
+processing operations.
+
+The processors managed by RTEMS use two Deterministic Priority scheduler
+instances capable of dealing with 256 priority levels.  The scheduler with
+index zero has the name @code{"IO  "}.  The scheduler with index one has the
+name @code{"WORK"}.  The scheduler assignments of the first, third and fourth
+processor are mandatory, so the system must have at least four processors,
+otherwise a fatal run-time error will occur during system startup.  The
+processor assignments for the fifth up to the eighth processor are optional so
+that the same application can be used for the normal and high-performance
+product lines.  The second processor has no scheduler assigned and runs Linux.
+A hypervisor will ensure that the two systems cannot interfere in an
+undesirable way.
+
+ at example
+ at group
+#define CONFIGURE_SMP_MAXIMUM_PROCESSORS 8
+
+#define CONFIGURE_MAXIMUM_PRIORITY 255
+
+/* Make the scheduler algorithm available */
+
+#define CONFIGURE_SCHEDULER_PRIORITY_SMP
+
+#include <rtems/scheduler.h>
+
+/* Create contexts for the two scheduler instances */
+
+RTEMS_SCHEDULER_CONTEXT_PRIORITY_SMP(io, CONFIGURE_MAXIMUM_PRIORITY + 1);
+
+RTEMS_SCHEDULER_CONTEXT_PRIORITY_SMP(work, CONFIGURE_MAXIMUM_PRIORITY + 1);
+
+/* Define the scheduler table */
+
+#define CONFIGURE_SCHEDULER_CONTROLS \
+  RTEMS_SCHEDULER_CONTROL_PRIORITY_SMP( \
+    io, \
+    rtems_build_name('I', 'O', ' ', ' ') \
+  ), \
+  RTEMS_SCHEDULER_CONTROL_PRIORITY_SMP( \
+    work, \
+    rtems_build_name('W', 'O', 'R', 'K') \
+  )
+
+/* Define the processor to scheduler assignments */
+
+#define CONFIGURE_SMP_SCHEDULER_ASSIGNMENTS \
+  RTEMS_SCHEDULER_ASSIGN(0, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_MANDATORY), \
+  RTEMS_SCHEDULER_ASSIGN_NO_SCHEDULER, \
+  RTEMS_SCHEDULER_ASSIGN(1, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_MANDATORY), \
+  RTEMS_SCHEDULER_ASSIGN(1, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_MANDATORY), \
+  RTEMS_SCHEDULER_ASSIGN(1, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
+  RTEMS_SCHEDULER_ASSIGN(1, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
+  RTEMS_SCHEDULER_ASSIGN(1, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
+  RTEMS_SCHEDULER_ASSIGN(1, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL)
+ at end group
+ at end example
+
+ at c
 @c === SMP Specific Configuration Parameters ===
 @c
 @section SMP Specific Configuration Parameters
@@ -3804,7 +3985,7 @@ configuration parameters which apply.
 @c
 @c === CONFIGURE_SMP_APPLICATION ===
 @c
- at subsection Specify Application Uses Multiple Cores (is SMP)
+ at subsection Enable SMP Support for Applications
 
 @findex CONFIGURE_SMP_APPLICATION
 
@@ -3819,16 +4000,16 @@ Boolean feature macro.
 Defined or undefined.
 
 @item DEFAULT VALUE:
-The default value is 1, (if CONFIGURE_SMP_APPLICATION is defined).
+This is not defined by default.
 
 @end table
 
 @subheading DESCRIPTION:
- at code{CONFIGURE_SMP_APPLICATION} must be defined if the application is
-to make use of multiple CPU cores in an SMP target system.
+ at code{CONFIGURE_SMP_APPLICATION} must be defined to enable SMP support for the
+application.
 
 @subheading NOTES:
-None.
+This define may go away in the future in case all RTEMS components are SMP ready.
 
 @c
 @c === CONFIGURE_SMP_MAXIMUM_PROCESSORS ===
@@ -3854,10 +4035,10 @@ The default value is 1, (if CONFIGURE_SMP_APPLICATION is defined).
 
 @subheading DESCRIPTION:
 @code{CONFIGURE_SMP_MAXIMUM_PROCESSORS} must be set to the number of
-CPU cores in the SMP configuration.
+processors in the SMP configuration.
 
 @subheading NOTES:
-If there are more cores available than configured, the rest will be
+If there are more processors available than configured, the rest will be
 ignored.
 
 @c
diff --git a/testsuites/smptests/Makefile.am b/testsuites/smptests/Makefile.am
index 82f5322..e757cf2 100644
--- a/testsuites/smptests/Makefile.am
+++ b/testsuites/smptests/Makefile.am
@@ -1,8 +1,6 @@
 ACLOCAL_AMFLAGS = -I ../aclocal
 
 SUBDIRS =
-SUBDIRS += smpload01
-
 if SMPTESTS
 SUBDIRS += smp01
 SUBDIRS += smp02
@@ -16,9 +14,16 @@ SUBDIRS += smpatomic01
 SUBDIRS += smpfatal01
 SUBDIRS += smpfatal02
 SUBDIRS += smpfatal03
+SUBDIRS += smpfatal04
+SUBDIRS += smpfatal05
+SUBDIRS += smpfatal06
+SUBDIRS += smpfatal07
+SUBDIRS += smpfatal08
+SUBDIRS += smpload01
 SUBDIRS += smplock01
 SUBDIRS += smpmigration01
 SUBDIRS += smpscheduler01
+SUBDIRS += smpscheduler02
 SUBDIRS += smpsignal01
 SUBDIRS += smpswitchextension01
 SUBDIRS += smpthreadlife01
diff --git a/testsuites/smptests/configure.ac b/testsuites/smptests/configure.ac
index 97b825b..ee36b50 100644
--- a/testsuites/smptests/configure.ac
+++ b/testsuites/smptests/configure.ac
@@ -57,7 +57,6 @@ AM_CONDITIONAL(HAS_CPUSET,test x"${ac_cv_header_sys_cpuset_h}" = x"yes")
 
 # Explicitly list all Makefiles here
 AC_CONFIG_FILES([Makefile
-smpload01/Makefile
 smp01/Makefile
 smp02/Makefile
 smp03/Makefile
@@ -70,12 +69,19 @@ smpatomic01/Makefile
 smpfatal01/Makefile
 smpfatal02/Makefile
 smpfatal03/Makefile
+smpfatal04/Makefile
+smpfatal05/Makefile
+smpfatal06/Makefile
+smpfatal07/Makefile
+smpfatal08/Makefile
+smpload01/Makefile
 smplock01/Makefile
 smpmigration01/Makefile
 smppsxaffinity01/Makefile
 smppsxaffinity02/Makefile
 smppsxsignal01/Makefile
 smpscheduler01/Makefile
+smpscheduler02/Makefile
 smpsignal01/Makefile
 smpswitchextension01/Makefile
 smpthreadlife01/Makefile
diff --git a/testsuites/smptests/smpfatal04/Makefile.am b/testsuites/smptests/smpfatal04/Makefile.am
new file mode 100644
index 0000000..0ee1f36
--- /dev/null
+++ b/testsuites/smptests/smpfatal04/Makefile.am
@@ -0,0 +1,19 @@
+rtems_tests_PROGRAMS = smpfatal04
+smpfatal04_SOURCES = init.c
+
+dist_rtems_tests_DATA = smpfatal04.scn smpfatal04.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 = $(smpfatal04_OBJECTS)
+LINK_LIBS = $(smpfatal04_LDLIBS)
+
+smpfatal04$(EXEEXT): $(smpfatal04_OBJECTS) $(smpfatal04_DEPENDENCIES)
+	@rm -f smpfatal04$(EXEEXT)
+	$(make-exe)
+
+include $(top_srcdir)/../automake/local.am
diff --git a/testsuites/smptests/smpfatal04/init.c b/testsuites/smptests/smpfatal04/init.c
new file mode 100644
index 0000000..39ceebf
--- /dev/null
+++ b/testsuites/smptests/smpfatal04/init.c
@@ -0,0 +1,71 @@
+/*
+ * 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.org/license/LICENSE.
+ */
+
+#ifdef HAVE_CONFIG_H
+  #include "config.h"
+#endif
+
+#include <rtems.h>
+#include <rtems/test.h>
+#include <rtems/score/smpimpl.h>
+
+#include <assert.h>
+#include <stdlib.h>
+
+const char rtems_test_name[] = "SMPFATAL 4";
+
+static void Init(rtems_task_argument arg)
+{
+  assert(0);
+}
+
+static void fatal_extension(
+  rtems_fatal_source source,
+  bool is_internal,
+  rtems_fatal_code code
+)
+{
+  rtems_test_begink();
+
+  if (
+    source == RTEMS_FATAL_SOURCE_SMP
+      && !is_internal
+      && code == SMP_FATAL_BOOT_PROCESSOR_NOT_ASSIGNED_TO_SCHEDULER
+  ) {
+    rtems_test_endk();
+  }
+}
+
+#define CONFIGURE_APPLICATION_DOES_NOT_NEED_CLOCK_DRIVER
+#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
+
+#define CONFIGURE_INITIAL_EXTENSIONS \
+  { .fatal = fatal_extension }, \
+  RTEMS_TEST_INITIAL_EXTENSION
+
+#define CONFIGURE_SMP_APPLICATION
+
+#define CONFIGURE_SMP_MAXIMUM_PROCESSORS 1
+
+#define CONFIGURE_SCHEDULER_CONTROLS
+
+#define CONFIGURE_SMP_SCHEDULER_ASSIGNMENTS RTEMS_SCHEDULER_ASSIGN_NO_SCHEDULER
+
+#define CONFIGURE_MAXIMUM_TASKS 1
+
+#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
+
+#define CONFIGURE_INIT
+
+#include <rtems/confdefs.h>
diff --git a/testsuites/smptests/smpfatal04/smpfatal04.doc b/testsuites/smptests/smpfatal04/smpfatal04.doc
new file mode 100644
index 0000000..cac6286
--- /dev/null
+++ b/testsuites/smptests/smpfatal04/smpfatal04.doc
@@ -0,0 +1,11 @@
+This file describes the directives and concepts tested by this test set.
+
+test set name: smpfatal04
+
+directives:
+
+  - _SMP_Handler_initialize()
+
+concepts:
+
+  - Ensure that the boot processor has a scheduler assigned.
diff --git a/testsuites/smptests/smpfatal04/smpfatal04.scn b/testsuites/smptests/smpfatal04/smpfatal04.scn
new file mode 100644
index 0000000..d449a9e
--- /dev/null
+++ b/testsuites/smptests/smpfatal04/smpfatal04.scn
@@ -0,0 +1,2 @@
+*** BEGIN OF TEST SMPFATAL 4 ***
+*** END OF TEST SMPFATAL 4 ***
diff --git a/testsuites/smptests/smpfatal05/Makefile.am b/testsuites/smptests/smpfatal05/Makefile.am
new file mode 100644
index 0000000..066498d
--- /dev/null
+++ b/testsuites/smptests/smpfatal05/Makefile.am
@@ -0,0 +1,19 @@
+rtems_tests_PROGRAMS = smpfatal05
+smpfatal05_SOURCES = init.c
+
+dist_rtems_tests_DATA = smpfatal05.scn smpfatal05.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 = $(smpfatal05_OBJECTS)
+LINK_LIBS = $(smpfatal05_LDLIBS)
+
+smpfatal05$(EXEEXT): $(smpfatal05_OBJECTS) $(smpfatal05_DEPENDENCIES)
+	@rm -f smpfatal05$(EXEEXT)
+	$(make-exe)
+
+include $(top_srcdir)/../automake/local.am
diff --git a/testsuites/smptests/smpfatal05/init.c b/testsuites/smptests/smpfatal05/init.c
new file mode 100644
index 0000000..37b3dee
--- /dev/null
+++ b/testsuites/smptests/smpfatal05/init.c
@@ -0,0 +1,90 @@
+/*
+ * 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.org/license/LICENSE.
+ */
+
+#ifdef HAVE_CONFIG_H
+  #include "config.h"
+#endif
+
+#include <rtems.h>
+#include <rtems/test.h>
+#include <rtems/score/smpimpl.h>
+
+#include <assert.h>
+#include <stdlib.h>
+
+const char rtems_test_name[] = "SMPFATAL 5";
+
+static void Init(rtems_task_argument arg)
+{
+  assert(0);
+}
+
+static void fatal_extension(
+  rtems_fatal_source source,
+  bool is_internal,
+  rtems_fatal_code code
+)
+{
+  rtems_test_begink();
+
+  if (
+    source == RTEMS_FATAL_SOURCE_SMP
+      && !is_internal
+      && code == SMP_FATAL_MANDATORY_PROCESSOR_NOT_PRESENT
+  ) {
+    rtems_test_endk();
+  }
+}
+
+#define CONFIGURE_APPLICATION_DOES_NOT_NEED_CLOCK_DRIVER
+#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
+
+#define CONFIGURE_INITIAL_EXTENSIONS \
+  { .fatal = fatal_extension }, \
+  RTEMS_TEST_INITIAL_EXTENSION
+
+#define CONFIGURE_SMP_APPLICATION
+
+/* Lets see when the first RTEMS system hits this limit */
+#define CONFIGURE_SMP_MAXIMUM_PROCESSORS 64
+
+#define CONFIGURE_SCHEDULER_SIMPLE_SMP
+
+#include <rtems/scheduler.h>
+
+RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(a);
+
+#define CONFIGURE_SCHEDULER_CONTROLS \
+  RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(a, rtems_build_name('S', 'I', 'M', 'P'))
+
+#define ASSIGN \
+  RTEMS_SCHEDULER_ASSIGN(0, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_MANDATORY)
+
+#define CONFIGURE_SMP_SCHEDULER_ASSIGNMENTS \
+ ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, \
+ ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, \
+ ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, \
+ ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, \
+ ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, \
+ ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, \
+ ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, \
+ ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN
+
+#define CONFIGURE_MAXIMUM_TASKS 1
+
+#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
+
+#define CONFIGURE_INIT
+
+#include <rtems/confdefs.h>
diff --git a/testsuites/smptests/smpfatal05/smpfatal05.doc b/testsuites/smptests/smpfatal05/smpfatal05.doc
new file mode 100644
index 0000000..91c37ad
--- /dev/null
+++ b/testsuites/smptests/smpfatal05/smpfatal05.doc
@@ -0,0 +1,11 @@
+This file describes the directives and concepts tested by this test set.
+
+test set name: smpfatal05
+
+directives:
+
+  - _SMP_Handler_initialize()
+
+concepts:
+
+  - Ensure that all mandatory processors are present.
diff --git a/testsuites/smptests/smpfatal05/smpfatal05.scn b/testsuites/smptests/smpfatal05/smpfatal05.scn
new file mode 100644
index 0000000..d3dcb82
--- /dev/null
+++ b/testsuites/smptests/smpfatal05/smpfatal05.scn
@@ -0,0 +1,2 @@
+*** BEGIN OF TEST SMPFATAL 5 ***
+*** END OF TEST SMPFATAL 5 ***
diff --git a/testsuites/smptests/smpfatal06/Makefile.am b/testsuites/smptests/smpfatal06/Makefile.am
new file mode 100644
index 0000000..c0bdf5b
--- /dev/null
+++ b/testsuites/smptests/smpfatal06/Makefile.am
@@ -0,0 +1,19 @@
+rtems_tests_PROGRAMS = smpfatal06
+smpfatal06_SOURCES = init.c
+
+dist_rtems_tests_DATA = smpfatal06.scn smpfatal06.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 = $(smpfatal06_OBJECTS)
+LINK_LIBS = $(smpfatal06_LDLIBS)
+
+smpfatal06$(EXEEXT): $(smpfatal06_OBJECTS) $(smpfatal06_DEPENDENCIES)
+	@rm -f smpfatal06$(EXEEXT)
+	$(make-exe)
+
+include $(top_srcdir)/../automake/local.am
diff --git a/testsuites/smptests/smpfatal06/init.c b/testsuites/smptests/smpfatal06/init.c
new file mode 100644
index 0000000..739da7a
--- /dev/null
+++ b/testsuites/smptests/smpfatal06/init.c
@@ -0,0 +1,81 @@
+/*
+ * 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.org/license/LICENSE.
+ */
+
+#ifdef HAVE_CONFIG_H
+  #include "config.h"
+#endif
+
+#include <rtems.h>
+#include <rtems/test.h>
+#include <rtems/score/smpimpl.h>
+
+#include <assert.h>
+#include <stdlib.h>
+
+const char rtems_test_name[] = "SMPFATAL 6";
+
+static void Init(rtems_task_argument arg)
+{
+  assert(0);
+}
+
+static void fatal_extension(
+  rtems_fatal_source source,
+  bool is_internal,
+  rtems_fatal_code code
+)
+{
+  rtems_test_begink();
+
+  if (
+    source == RTEMS_FATAL_SOURCE_SMP
+      && !is_internal
+      && code == SMP_FATAL_SCHEDULER_WITHOUT_PROCESSORS
+  ) {
+    rtems_test_endk();
+  }
+}
+
+#define CONFIGURE_APPLICATION_DOES_NOT_NEED_CLOCK_DRIVER
+#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
+
+#define CONFIGURE_INITIAL_EXTENSIONS \
+  { .fatal = fatal_extension }, \
+  RTEMS_TEST_INITIAL_EXTENSION
+
+#define CONFIGURE_SMP_APPLICATION
+
+#define CONFIGURE_SMP_MAXIMUM_PROCESSORS 1
+
+#define CONFIGURE_SCHEDULER_SIMPLE_SMP
+
+#include <rtems/scheduler.h>
+
+RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(a);
+RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(b);
+
+#define CONFIGURE_SCHEDULER_CONTROLS \
+  RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(a, rtems_build_name('S', 'I', 'M', 'P')), \
+  RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(b, rtems_build_name('S', 'I', 'M', 'P'))
+
+#define CONFIGURE_SMP_SCHEDULER_ASSIGNMENTS \
+  RTEMS_SCHEDULER_ASSIGN(0, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_MANDATORY)
+
+#define CONFIGURE_MAXIMUM_TASKS 1
+
+#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
+
+#define CONFIGURE_INIT
+
+#include <rtems/confdefs.h>
diff --git a/testsuites/smptests/smpfatal06/smpfatal06.doc b/testsuites/smptests/smpfatal06/smpfatal06.doc
new file mode 100644
index 0000000..e35b3b0
--- /dev/null
+++ b/testsuites/smptests/smpfatal06/smpfatal06.doc
@@ -0,0 +1,11 @@
+This file describes the directives and concepts tested by this test set.
+
+test set name: smpfatal06
+
+directives:
+
+  - _SMP_Handler_initialize()
+
+concepts:
+
+  - Ensure that a scheduler without processor leads to a fatal error.
diff --git a/testsuites/smptests/smpfatal06/smpfatal06.scn b/testsuites/smptests/smpfatal06/smpfatal06.scn
new file mode 100644
index 0000000..575b2b3
--- /dev/null
+++ b/testsuites/smptests/smpfatal06/smpfatal06.scn
@@ -0,0 +1,2 @@
+*** TEST SMPFATAL 6 ***
+*** END OF TEST SMPFATAL 6 ***
diff --git a/testsuites/smptests/smpfatal07/Makefile.am b/testsuites/smptests/smpfatal07/Makefile.am
new file mode 100644
index 0000000..724ff93
--- /dev/null
+++ b/testsuites/smptests/smpfatal07/Makefile.am
@@ -0,0 +1,19 @@
+rtems_tests_PROGRAMS = smpfatal07
+smpfatal07_SOURCES = init.c
+
+dist_rtems_tests_DATA = smpfatal07.scn smpfatal07.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 = $(smpfatal07_OBJECTS)
+LINK_LIBS = $(smpfatal07_LDLIBS)
+
+smpfatal07$(EXEEXT): $(smpfatal07_OBJECTS) $(smpfatal07_DEPENDENCIES)
+	@rm -f smpfatal07$(EXEEXT)
+	$(make-exe)
+
+include $(top_srcdir)/../automake/local.am
diff --git a/testsuites/smptests/smpfatal07/init.c b/testsuites/smptests/smpfatal07/init.c
new file mode 100644
index 0000000..1262742
--- /dev/null
+++ b/testsuites/smptests/smpfatal07/init.c
@@ -0,0 +1,75 @@
+/*
+ * 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.org/license/LICENSE.
+ */
+
+#ifdef HAVE_CONFIG_H
+  #include "config.h"
+#endif
+
+#include <rtems.h>
+#include <rtems/test.h>
+#include <rtems/score/smpimpl.h>
+#include <rtems/score/threadimpl.h>
+
+#include <assert.h>
+#include <stdlib.h>
+
+const char rtems_test_name[] = "SMPFATAL 7";
+
+static void Init(rtems_task_argument arg)
+{
+  Per_CPU_Control *cpu_self;
+
+  _Thread_Disable_dispatch();
+  cpu_self = _Per_CPU_Get();
+  cpu_self->started = false;
+  _SMP_Start_multitasking_on_secondary_processor();
+
+  assert(0);
+}
+
+static void fatal_extension(
+  rtems_fatal_source source,
+  bool is_internal,
+  rtems_fatal_code code
+)
+{
+  rtems_test_begink();
+
+  if (
+    source == RTEMS_FATAL_SOURCE_SMP
+      && !is_internal
+      && code == SMP_FATAL_MULTITASKING_START_ON_UNASSIGNED_PROCESSOR
+  ) {
+    rtems_test_endk();
+  }
+}
+
+#define CONFIGURE_APPLICATION_DOES_NOT_NEED_CLOCK_DRIVER
+#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
+
+#define CONFIGURE_INITIAL_EXTENSIONS \
+  { .fatal = fatal_extension }, \
+  RTEMS_TEST_INITIAL_EXTENSION
+
+#define CONFIGURE_SMP_APPLICATION
+
+#define CONFIGURE_SMP_MAXIMUM_PROCESSORS 1
+
+#define CONFIGURE_MAXIMUM_TASKS 1
+
+#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
+
+#define CONFIGURE_INIT
+
+#include <rtems/confdefs.h>
diff --git a/testsuites/smptests/smpfatal07/smpfatal07.doc b/testsuites/smptests/smpfatal07/smpfatal07.doc
new file mode 100644
index 0000000..5f37225
--- /dev/null
+++ b/testsuites/smptests/smpfatal07/smpfatal07.doc
@@ -0,0 +1,12 @@
+This file describes the directives and concepts tested by this test set.
+
+test set name: smpfatal07
+
+directives:
+
+  - _SMP_Start_multitasking_on_secondary_processor()
+
+concepts:
+
+  - Ensure that a multitasking start on an unassigned processor leads to a
+    fatal error.
diff --git a/testsuites/smptests/smpfatal07/smpfatal07.scn b/testsuites/smptests/smpfatal07/smpfatal07.scn
new file mode 100644
index 0000000..10252a6
--- /dev/null
+++ b/testsuites/smptests/smpfatal07/smpfatal07.scn
@@ -0,0 +1,2 @@
+*** TEST SMPFATAL 7 ***
+*** END OF TEST SMPFATAL 7 ***
diff --git a/testsuites/smptests/smpfatal08/Makefile.am b/testsuites/smptests/smpfatal08/Makefile.am
new file mode 100644
index 0000000..da4e316
--- /dev/null
+++ b/testsuites/smptests/smpfatal08/Makefile.am
@@ -0,0 +1,19 @@
+rtems_tests_PROGRAMS = smpfatal08
+smpfatal08_SOURCES = init.c
+
+dist_rtems_tests_DATA = smpfatal08.scn smpfatal08.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 = $(smpfatal08_OBJECTS)
+LINK_LIBS = $(smpfatal08_LDLIBS)
+
+smpfatal08$(EXEEXT): $(smpfatal08_OBJECTS) $(smpfatal08_DEPENDENCIES)
+	@rm -f smpfatal08$(EXEEXT)
+	$(make-exe)
+
+include $(top_srcdir)/../automake/local.am
diff --git a/testsuites/smptests/smpfatal08/init.c b/testsuites/smptests/smpfatal08/init.c
new file mode 100644
index 0000000..59fe4a6
--- /dev/null
+++ b/testsuites/smptests/smpfatal08/init.c
@@ -0,0 +1,132 @@
+/*
+ * 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.org/license/LICENSE.
+ */
+
+#ifdef HAVE_CONFIG_H
+  #include "config.h"
+#endif
+
+#include <rtems.h>
+#include <rtems/test.h>
+#include <rtems/score/smpimpl.h>
+
+#include <assert.h>
+#include <stdlib.h>
+
+const char rtems_test_name[] = "SMPFATAL 8";
+
+/*
+ * This test is a hack since there is no easy way to test this fatal error path
+ * without BSP support.
+ */
+
+#if defined(__PPC__)
+void qoriq_secondary_cpu_initialize(void)
+{
+  /* Provided to avoid multiple definitions of the CPU SMP support functions */
+}
+#endif
+
+#if defined(__sparc__)
+void leon3_secondary_cpu_initialize(uint32_t cpu_index)
+{
+  (void) cpu_index;
+
+  /* Provided to avoid multiple definitions of the CPU SMP support functions */
+}
+#endif
+
+uint32_t _CPU_SMP_Initialize(void)
+{
+  return 2;
+}
+
+bool _CPU_SMP_Start_processor(uint32_t cpu_index)
+{
+  (void) cpu_index;
+
+  return false;
+}
+
+void _CPU_SMP_Finalize_initialization(uint32_t cpu_count)
+{
+  (void) cpu_count;
+
+  assert(0);
+}
+
+#if !defined(__leon__) && !defined(__PPC__) && !defined(__arm__)
+uint32_t _CPU_SMP_Get_current_processor(void)
+{
+  return 0;
+}
+#endif
+
+void _CPU_SMP_Send_interrupt(uint32_t target_processor_index)
+{
+  (void) target_processor_index;
+}
+
+static void Init(rtems_task_argument arg)
+{
+  assert(0);
+}
+
+static void fatal_extension(
+  rtems_fatal_source source,
+  bool is_internal,
+  rtems_fatal_code code
+)
+{
+  rtems_test_begink();
+
+  if (
+    source == RTEMS_FATAL_SOURCE_SMP
+      && !is_internal
+      && code == SMP_FATAL_START_OF_MANDATORY_PROCESSOR_FAILED
+  ) {
+    rtems_test_endk();
+  }
+}
+
+#define CONFIGURE_APPLICATION_DOES_NOT_NEED_CLOCK_DRIVER
+#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
+
+#define CONFIGURE_INITIAL_EXTENSIONS \
+  { .fatal = fatal_extension }, \
+  RTEMS_TEST_INITIAL_EXTENSION
+
+#define CONFIGURE_SMP_APPLICATION
+
+#define CONFIGURE_SMP_MAXIMUM_PROCESSORS 2
+
+#define CONFIGURE_SCHEDULER_SIMPLE_SMP
+
+#include <rtems/scheduler.h>
+
+RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(a);
+
+#define CONFIGURE_SCHEDULER_CONTROLS \
+  RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(a, rtems_build_name('S', 'I', 'M', 'P'))
+
+#define CONFIGURE_SMP_SCHEDULER_ASSIGNMENTS \
+  RTEMS_SCHEDULER_ASSIGN(0, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_MANDATORY), \
+  RTEMS_SCHEDULER_ASSIGN(0, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_MANDATORY)
+
+#define CONFIGURE_MAXIMUM_TASKS 1
+
+#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
+
+#define CONFIGURE_INIT
+
+#include <rtems/confdefs.h>
diff --git a/testsuites/smptests/smpfatal08/smpfatal08.doc b/testsuites/smptests/smpfatal08/smpfatal08.doc
new file mode 100644
index 0000000..df52c96
--- /dev/null
+++ b/testsuites/smptests/smpfatal08/smpfatal08.doc
@@ -0,0 +1,11 @@
+This file describes the directives and concepts tested by this test set.
+
+test set name: smpfatal08
+
+directives:
+
+  - _SMP_Handler_initialize()
+
+concepts:
+
+  - Ensure that a failed start of a mandatory processor leads to a fatal error.
diff --git a/testsuites/smptests/smpfatal08/smpfatal08.scn b/testsuites/smptests/smpfatal08/smpfatal08.scn
new file mode 100644
index 0000000..10252a6
--- /dev/null
+++ b/testsuites/smptests/smpfatal08/smpfatal08.scn
@@ -0,0 +1,2 @@
+*** TEST SMPFATAL 7 ***
+*** END OF TEST SMPFATAL 7 ***
diff --git a/testsuites/smptests/smpscheduler02/Makefile.am b/testsuites/smptests/smpscheduler02/Makefile.am
new file mode 100644
index 0000000..48a7072
--- /dev/null
+++ b/testsuites/smptests/smpscheduler02/Makefile.am
@@ -0,0 +1,19 @@
+rtems_tests_PROGRAMS = smpscheduler02
+smpscheduler02_SOURCES = init.c
+
+dist_rtems_tests_DATA = smpscheduler02.scn smpscheduler02.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 = $(smpscheduler02_OBJECTS)
+LINK_LIBS = $(smpscheduler02_LDLIBS)
+
+smpscheduler02$(EXEEXT): $(smpscheduler02_OBJECTS) $(smpscheduler02_DEPENDENCIES)
+	@rm -f smpscheduler02$(EXEEXT)
+	$(make-exe)
+
+include $(top_srcdir)/../automake/local.am
diff --git a/testsuites/smptests/smpscheduler02/init.c b/testsuites/smptests/smpscheduler02/init.c
new file mode 100644
index 0000000..f958744
--- /dev/null
+++ b/testsuites/smptests/smpscheduler02/init.c
@@ -0,0 +1,222 @@
+/*
+ * 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.org/license/LICENSE.
+ */
+
+#ifdef HAVE_CONFIG_H
+  #include "config.h"
+#endif
+
+#include <rtems.h>
+#include <rtems/libcsupport.h>
+
+#include "tmacros.h"
+
+const char rtems_test_name[] = "SMPSCHEDULER 2";
+
+#if defined(__RTEMS_HAVE_SYS_CPUSET_H__)
+
+#define CPU_COUNT 2
+
+#define SCHED_A rtems_build_name(' ', ' ', ' ', 'A')
+
+#define SCHED_B rtems_build_name(' ', ' ', ' ', 'B')
+
+static rtems_id main_task_id;
+
+static void task(rtems_task_argument arg)
+{
+  rtems_status_code sc;
+
+  (void) arg;
+
+  rtems_test_assert(rtems_get_current_processor() == 1);
+
+  sc = rtems_event_transient_send(main_task_id);
+  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+
+  while (1) {
+    /* Do nothing */
+  }
+}
+
+static void test(void)
+{
+  rtems_status_code sc;
+  rtems_id task_id;
+  rtems_id scheduler_id;
+  rtems_id scheduler_a_id;
+  rtems_id scheduler_b_id;
+  cpu_set_t cpuset;
+  cpu_set_t first_cpu;
+  cpu_set_t second_cpu;
+  cpu_set_t all_cpus;
+
+  main_task_id = rtems_task_self();
+
+  CPU_ZERO(&first_cpu);
+  CPU_SET(0, &first_cpu);
+
+  CPU_ZERO(&second_cpu);
+  CPU_SET(1, &second_cpu);
+
+  CPU_ZERO(&all_cpus);
+  CPU_SET(0, &all_cpus);
+  CPU_SET(1, &all_cpus);
+
+  rtems_test_assert(rtems_get_current_processor() == 0);
+
+  sc = rtems_scheduler_ident(SCHED_A, &scheduler_a_id);
+  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+
+  sc = rtems_scheduler_ident(SCHED_B, &scheduler_b_id);
+  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+  rtems_test_assert(scheduler_a_id != scheduler_b_id);
+
+  CPU_ZERO(&cpuset);
+  sc = rtems_scheduler_get_processor_set(
+    scheduler_a_id,
+    sizeof(cpuset),
+    &cpuset
+  );
+  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+  rtems_test_assert(CPU_EQUAL(&cpuset, &first_cpu));
+
+  CPU_ZERO(&cpuset);
+  sc = rtems_scheduler_get_processor_set(
+    scheduler_b_id,
+    sizeof(cpuset),
+    &cpuset
+  );
+  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+  rtems_test_assert(CPU_EQUAL(&cpuset, &second_cpu));
+
+  sc = rtems_task_create(
+    rtems_build_name('T', 'A', 'S', 'K'),
+    1,
+    RTEMS_MINIMUM_STACK_SIZE,
+    RTEMS_DEFAULT_MODES,
+    RTEMS_DEFAULT_ATTRIBUTES,
+    &task_id
+  );
+  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+
+  sc = rtems_task_get_scheduler(task_id, &scheduler_id);
+  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+  rtems_test_assert(scheduler_id == scheduler_a_id);
+
+  CPU_ZERO(&cpuset);
+  sc = rtems_task_get_affinity(task_id, sizeof(cpuset), &cpuset);
+  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+  rtems_test_assert(CPU_EQUAL(&cpuset, &first_cpu));
+
+  sc = rtems_task_set_scheduler(task_id, scheduler_b_id);
+  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+
+  sc = rtems_task_get_scheduler(task_id, &scheduler_id);
+  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+  rtems_test_assert(scheduler_id == scheduler_b_id);
+
+  CPU_ZERO(&cpuset);
+  sc = rtems_task_get_affinity(task_id, sizeof(cpuset), &cpuset);
+  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+  rtems_test_assert(CPU_EQUAL(&cpuset, &second_cpu));
+
+  sc = rtems_task_set_affinity(task_id, sizeof(all_cpus), &all_cpus);
+  rtems_test_assert(sc == RTEMS_INVALID_NUMBER);
+
+  sc = rtems_task_set_affinity(task_id, sizeof(first_cpu), &first_cpu);
+  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+
+  sc = rtems_task_get_scheduler(task_id, &scheduler_id);
+  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+  rtems_test_assert(scheduler_id == scheduler_a_id);
+
+  sc = rtems_task_set_affinity(task_id, sizeof(second_cpu), &second_cpu);
+  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+
+  sc = rtems_task_get_scheduler(task_id, &scheduler_id);
+  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+  rtems_test_assert(scheduler_id == scheduler_b_id);
+
+  sc = rtems_task_start(task_id, task, 0);
+  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+
+  sc = rtems_task_set_scheduler(task_id, scheduler_a_id);
+  rtems_test_assert(sc == RTEMS_INCORRECT_STATE);
+
+  sc = rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+
+  sc = rtems_task_delete(task_id);
+  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+}
+
+#else /* defined(__RTEMS_HAVE_SYS_CPUSET_H__) */
+
+static void test(void)
+{
+  /* Nothing to do */
+}
+
+#endif /* defined(__RTEMS_HAVE_SYS_CPUSET_H__) */
+
+static void Init(rtems_task_argument arg)
+{
+  rtems_resource_snapshot snapshot;
+
+  TEST_BEGIN();
+
+  rtems_resource_snapshot_take(&snapshot);
+
+  test();
+
+  rtems_test_assert(rtems_resource_snapshot_check(&snapshot));
+
+  TEST_END();
+  rtems_test_exit(0);
+}
+
+#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
+#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
+
+#define CONFIGURE_SMP_APPLICATION
+
+#define CONFIGURE_SMP_MAXIMUM_PROCESSORS CPU_COUNT
+
+#define CONFIGURE_MAXIMUM_PRIORITY 255
+
+#define CONFIGURE_SCHEDULER_PRIORITY_SMP
+
+#include <rtems/scheduler.h>
+
+RTEMS_SCHEDULER_CONTEXT_PRIORITY_SMP(a, CONFIGURE_MAXIMUM_PRIORITY + 1);
+
+RTEMS_SCHEDULER_CONTEXT_PRIORITY_SMP(b, CONFIGURE_MAXIMUM_PRIORITY + 1);
+
+#define CONFIGURE_SCHEDULER_CONTROLS \
+  RTEMS_SCHEDULER_CONTROL_PRIORITY_SMP(a, SCHED_A), \
+  RTEMS_SCHEDULER_CONTROL_PRIORITY_SMP(b, SCHED_B)
+
+#define CONFIGURE_SMP_SCHEDULER_ASSIGNMENTS \
+  RTEMS_SCHEDULER_ASSIGN(0, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_MANDATORY), \
+  RTEMS_SCHEDULER_ASSIGN(1, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_MANDATORY)
+
+#define CONFIGURE_MAXIMUM_TASKS CPU_COUNT
+
+#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
+
+#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
+
+#define CONFIGURE_INIT
+
+#include <rtems/confdefs.h>
diff --git a/testsuites/smptests/smpscheduler02/smpscheduler02.doc b/testsuites/smptests/smpscheduler02/smpscheduler02.doc
new file mode 100644
index 0000000..13c35c0
--- /dev/null
+++ b/testsuites/smptests/smpscheduler02/smpscheduler02.doc
@@ -0,0 +1,12 @@
+This file describes the directives and concepts tested by this test set.
+
+test set name: smpscheduler02
+
+directives:
+
+  - rtems_task_set_scheduler()
+  - rtems_task_start()
+
+concepts:
+
+  - Ensure that start of a thread for another partition works.
diff --git a/testsuites/smptests/smpscheduler02/smpscheduler02.scn b/testsuites/smptests/smpscheduler02/smpscheduler02.scn
new file mode 100644
index 0000000..47903c4
--- /dev/null
+++ b/testsuites/smptests/smpscheduler02/smpscheduler02.scn
@@ -0,0 +1,2 @@
+*** BEGIN OF TEST SMPSCHEDULER 2 ***
+*** END OF TEST SMPSCHEDULER 2 ***
diff --git a/testsuites/sptests/spscheduler01/init.c b/testsuites/sptests/spscheduler01/init.c
index 6c19abc..30ea4ce 100644
--- a/testsuites/sptests/spscheduler01/init.c
+++ b/testsuites/sptests/spscheduler01/init.c
@@ -35,6 +35,7 @@ static void test_task_get_set_affinity(void)
 {
 #if defined(__RTEMS_HAVE_SYS_CPUSET_H__)
   rtems_id self_id = rtems_task_self();
+  rtems_id task_id;
   rtems_status_code sc;
   cpu_set_t cpusetone;
   cpu_set_t cpuset;
@@ -46,6 +47,16 @@ static void test_task_get_set_affinity(void)
   CPU_ZERO(&cpusetone);
   CPU_SET(0, &cpusetone);
 
+  sc = rtems_task_create(
+    rtems_build_name('T', 'A', 'S', 'K'),
+    2,
+    RTEMS_MINIMUM_STACK_SIZE,
+    RTEMS_DEFAULT_MODES,
+    RTEMS_DEFAULT_ATTRIBUTES,
+    &task_id
+  );
+  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+
   sc = rtems_task_get_affinity(RTEMS_SELF, sizeof(cpuset), NULL);
   rtems_test_assert(sc == RTEMS_INVALID_ADDRESS);
 
@@ -70,16 +81,19 @@ static void test_task_get_set_affinity(void)
   rtems_test_assert(CPU_EQUAL(&cpuset, &cpusetone));
 
   sc = rtems_task_set_affinity(RTEMS_SELF, sizeof(cpuset), &cpuset);
+  rtems_test_assert(sc == RTEMS_INVALID_NUMBER);
+
+  sc = rtems_task_set_affinity(self_id, sizeof(cpuset), &cpuset);
+  rtems_test_assert(sc == RTEMS_INVALID_NUMBER);
+
+  sc = rtems_task_set_affinity(task_id, sizeof(cpuset), &cpuset);
   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
 
-  sc = rtems_task_get_affinity(self_id, sizeof(cpuset), &cpuset);
+  sc = rtems_task_get_affinity(task_id, sizeof(cpuset), &cpuset);
   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
 
   rtems_test_assert(CPU_EQUAL(&cpuset, &cpusetone));
 
-  sc = rtems_task_set_affinity(self_id, sizeof(cpuset), &cpuset);
-  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
-
   cpusetbigone = CPU_ALLOC(big);
   rtems_test_assert(cpusetbigone != NULL);
 
@@ -89,12 +103,15 @@ static void test_task_get_set_affinity(void)
   CPU_ZERO_S(cpusetbigsize, cpusetbigone);
   CPU_SET_S(0, cpusetbigsize, cpusetbigone);
 
-  sc = rtems_task_get_affinity(RTEMS_SELF, cpusetbigsize, cpusetbig);
+  sc = rtems_task_get_affinity(task_id, cpusetbigsize, cpusetbig);
   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
 
   rtems_test_assert(CPU_EQUAL_S(cpusetbigsize, cpusetbig, cpusetbigone));
 
-  sc = rtems_task_set_affinity(RTEMS_SELF, cpusetbigsize, cpusetbig);
+  sc = rtems_task_set_affinity(task_id, cpusetbigsize, cpusetbig);
+  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+
+  sc = rtems_task_delete(task_id);
   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
 
   CPU_FREE(cpusetbig);




More information about the vc mailing list