summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2014-05-02 10:31:09 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2014-05-07 14:26:28 +0200
commit38b59a6d3052654e356ae16b4a243c362312acce (patch)
tree9d19ed78a331839a2f292572ddbfa44091efd347
parentscore: Delete _SMP_Test_message_default_handler (diff)
downloadrtems-38b59a6d3052654e356ae16b4a243c362312acce.tar.bz2
score: Implement forced thread migration
The current implementation of task migration in RTEMS has some implications with respect to the interrupt latency. It is crucial to preserve the system invariant that a task can execute on at most one processor in the system at a time. This is accomplished with a boolean indicator in the task context. The processor architecture specific low-level task context switch code will mark that a task context is no longer executing and waits that the heir context stopped execution before it restores the heir context and resumes execution of the heir task. So there is one point in time in which a processor is without a task. This is essential to avoid cyclic dependencies in case multiple tasks migrate at once. Otherwise some supervising entity is necessary to prevent life-locks. Such a global supervisor would lead to scalability problems so this approach is not used. Currently the thread dispatch is performed with interrupts disabled. So in case the heir task is currently executing on another processor then this prolongs the time of disabled interrupts since one processor has to wait for another processor to make progress. It is difficult to avoid this issue with the interrupt latency since interrupts normally store the context of the interrupted task on its stack. In case a task is marked as not executing we must not use its task stack to store such an interrupt context. We cannot use the heir stack before it stopped execution on another processor. So if we enable interrupts during this transition we have to provide an alternative task independent stack for this time frame. This issue needs further investigation.
-rw-r--r--c/src/lib/libbsp/sparc/shared/irq_asm.S20
-rw-r--r--c/src/lib/libcpu/powerpc/new-exceptions/cpu.c4
-rw-r--r--c/src/lib/libcpu/powerpc/new-exceptions/cpu_asm.S20
-rw-r--r--cpukit/libmisc/cpuuse/cpuusagereport.c2
-rw-r--r--cpukit/rtems/include/rtems/rtems/tasks.h2
-rw-r--r--cpukit/rtems/src/tasksetscheduler.c5
-rw-r--r--cpukit/score/cpu/arm/cpu.c12
-rw-r--r--cpukit/score/cpu/arm/cpu_asm.S20
-rw-r--r--cpukit/score/cpu/arm/rtems/score/cpu.h16
-rw-r--r--cpukit/score/cpu/i386/cpu.c18
-rw-r--r--cpukit/score/cpu/i386/cpu_asm.S29
-rw-r--r--cpukit/score/cpu/i386/rtems/score/cpu.h27
-rw-r--r--cpukit/score/cpu/no_cpu/rtems/score/cpu.h18
-rw-r--r--cpukit/score/cpu/powerpc/cpu.c4
-rw-r--r--cpukit/score/cpu/powerpc/rtems/score/cpu.h14
-rw-r--r--cpukit/score/cpu/sparc/cpu.c8
-rw-r--r--cpukit/score/cpu/sparc/rtems/score/cpu.h13
-rw-r--r--cpukit/score/include/rtems/score/percpu.h51
-rw-r--r--cpukit/score/include/rtems/score/scheduler.h2
-rw-r--r--cpukit/score/include/rtems/score/schedulerimpl.h24
-rw-r--r--cpukit/score/include/rtems/score/schedulersmp.h4
-rw-r--r--cpukit/score/include/rtems/score/schedulersmpimpl.h81
-rw-r--r--cpukit/score/include/rtems/score/statesimpl.h2
-rw-r--r--cpukit/score/include/rtems/score/thread.h25
-rw-r--r--cpukit/score/include/rtems/score/threadimpl.h68
-rw-r--r--cpukit/score/include/rtems/score/userextimpl.h18
-rw-r--r--cpukit/score/src/smp.c5
-rw-r--r--cpukit/score/src/threaddispatch.c46
-rw-r--r--cpukit/score/src/threadhandler.c4
-rw-r--r--cpukit/score/src/threadinitialize.c6
-rw-r--r--cpukit/score/src/threadrestart.c2
-rw-r--r--cpukit/score/src/threadstartmultitasking.c14
-rw-r--r--doc/user/smp.t46
-rw-r--r--testsuites/smptests/Makefile.am1
-rw-r--r--testsuites/smptests/configure.ac1
-rw-r--r--testsuites/smptests/smpmigration02/Makefile.am19
-rw-r--r--testsuites/smptests/smpmigration02/init.c253
-rw-r--r--testsuites/smptests/smpmigration02/smpmigration02.doc12
-rw-r--r--testsuites/smptests/smpmigration02/smpmigration02.scn7
-rw-r--r--testsuites/smptests/smpscheduler02/init.c4
-rw-r--r--testsuites/smptests/smpswitchextension01/smpswitchextension01.scn14
-rw-r--r--testsuites/sptests/spscheduler01/init.c8
-rw-r--r--testsuites/tmtests/tm26/task1.c2
43 files changed, 799 insertions, 152 deletions
diff --git a/c/src/lib/libbsp/sparc/shared/irq_asm.S b/c/src/lib/libbsp/sparc/shared/irq_asm.S
index 3a86ad50f2..8b152840ed 100644
--- a/c/src/lib/libbsp/sparc/shared/irq_asm.S
+++ b/c/src/lib/libbsp/sparc/shared/irq_asm.S
@@ -163,6 +163,21 @@ done_flushing:
nop
nop
+#if defined(RTEMS_SMP)
+ ! Indicate that this context is no longer executing
+ stb %g0, [%o0 + SPARC_CONTEXT_CONTROL_IS_EXECUTING_OFFSET]
+
+ ! Wait for context to stop execution if necessary
+1:
+ ldub [%o1 + SPARC_CONTEXT_CONTROL_IS_EXECUTING_OFFSET], %g1
+ cmp %g1, 0
+ bne 1b
+ mov 1, %g1
+
+ ! Indicate that this context is executing
+ stb %g1, [%o1 + SPARC_CONTEXT_CONTROL_IS_EXECUTING_OFFSET]
+#endif
+
ld [%o1 + G5_OFFSET], %g5 ! restore the global registers
ld [%o1 + G7_OFFSET], %g7
@@ -202,6 +217,11 @@ done_flushing:
SYM(_CPU_Context_restore):
save %sp, -CPU_MINIMUM_STACK_FRAME_SIZE, %sp
rd %psr, %o2
+#if defined(RTEMS_SMP)
+ ! On SPARC the restore path needs also a valid executing context on SMP
+ ! to update the is executing indicator.
+ mov %i0, %o0
+#endif
ba SYM(_CPU_Context_restore_heir)
mov %i0, %o1 ! in the delay slot
diff --git a/c/src/lib/libcpu/powerpc/new-exceptions/cpu.c b/c/src/lib/libcpu/powerpc/new-exceptions/cpu.c
index 73a1d3ece5..32c0489308 100644
--- a/c/src/lib/libcpu/powerpc/new-exceptions/cpu.c
+++ b/c/src/lib/libcpu/powerpc/new-exceptions/cpu.c
@@ -130,6 +130,10 @@ void _CPU_Context_Initialize(
the_ppc_context->msr = msr_value;
the_ppc_context->lr = (uint32_t) entry_point;
+#ifdef RTEMS_SMP
+ the_ppc_context->is_executing = false;
+#endif
+
#ifdef __ALTIVEC__
_CPU_Context_initialize_altivec( the_ppc_context );
#endif
diff --git a/c/src/lib/libcpu/powerpc/new-exceptions/cpu_asm.S b/c/src/lib/libcpu/powerpc/new-exceptions/cpu_asm.S
index dcd33df789..4e74996d4c 100644
--- a/c/src/lib/libcpu/powerpc/new-exceptions/cpu_asm.S
+++ b/c/src/lib/libcpu/powerpc/new-exceptions/cpu_asm.S
@@ -326,9 +326,29 @@ PROC (_CPU_Context_switch):
stw r2, PPC_CONTEXT_OFFSET_GPR2(r3)
+#ifdef RTEMS_SMP
+ /* Indicate that this context is no longer executing */
+ msync
+ li r5, 0
+ stb r5, PPC_CONTEXT_OFFSET_IS_EXECUTING(r3)
+#endif
+
/* Restore context from r4 */
restore_context:
+#ifdef RTEMS_SMP
+ /* Wait for context to stop execution if necessary */
+1:
+ lbz r5, PPC_CONTEXT_OFFSET_IS_EXECUTING(r4)
+ cmpwi r5, 0
+ bne 1b
+
+ /* Indicate that this context is executing */
+ li r5, 1
+ stb r5, PPC_CONTEXT_OFFSET_IS_EXECUTING(r4)
+ isync
+#endif
+
#ifdef __ALTIVEC__
mr r14, r4
.extern _CPU_Context_switch_altivec
diff --git a/cpukit/libmisc/cpuuse/cpuusagereport.c b/cpukit/libmisc/cpuuse/cpuusagereport.c
index 86b637707a..296fa28da5 100644
--- a/cpukit/libmisc/cpuuse/cpuusagereport.c
+++ b/cpukit/libmisc/cpuuse/cpuusagereport.c
@@ -43,7 +43,7 @@
}
#else
/* FIXME: Locking */
- if ( the_thread->is_executing ) {
+ if ( _Thread_Is_executing_on_a_processor( the_thread ) ) {
*time_of_context_switch =
_Thread_Get_CPU( the_thread )->time_of_last_context_switch;
return true;
diff --git a/cpukit/rtems/include/rtems/rtems/tasks.h b/cpukit/rtems/include/rtems/rtems/tasks.h
index 43e8c8ac9d..a14e865ada 100644
--- a/cpukit/rtems/include/rtems/rtems/tasks.h
+++ b/cpukit/rtems/include/rtems/rtems/tasks.h
@@ -569,8 +569,6 @@ rtems_status_code rtems_task_get_scheduler(
*
* @retval RTEMS_SUCCESSFUL Successful operation.
* @retval RTEMS_INVALID_ID Invalid task or scheduler identifier.
- * @retval RTEMS_INCORRECT_STATE The task is in the wrong state to perform a
- * scheduler change.
*
* @see rtems_scheduler_ident().
*/
diff --git a/cpukit/rtems/src/tasksetscheduler.c b/cpukit/rtems/src/tasksetscheduler.c
index 42c08bbb80..30c7c6b3e2 100644
--- a/cpukit/rtems/src/tasksetscheduler.c
+++ b/cpukit/rtems/src/tasksetscheduler.c
@@ -30,15 +30,14 @@ rtems_status_code rtems_task_set_scheduler(
if ( _Scheduler_Get_by_id( scheduler_id, &scheduler ) ) {
Thread_Control *the_thread;
Objects_Locations location;
- bool ok;
the_thread = _Thread_Get( id, &location );
switch ( location ) {
case OBJECTS_LOCAL:
- ok = _Scheduler_Set( scheduler, the_thread );
+ _Scheduler_Set( scheduler, the_thread );
_Objects_Put( &the_thread->Object );
- sc = ok ? RTEMS_SUCCESSFUL : RTEMS_INCORRECT_STATE;
+ sc = RTEMS_SUCCESSFUL;
break;
#if defined(RTEMS_MULTIPROCESSING)
case OBJECTS_REMOTE:
diff --git a/cpukit/score/cpu/arm/cpu.c b/cpukit/score/cpu/arm/cpu.c
index 24a9249300..91109e4e1d 100644
--- a/cpukit/score/cpu/arm/cpu.c
+++ b/cpukit/score/cpu/arm/cpu.c
@@ -50,6 +50,14 @@
);
#endif
+#ifdef RTEMS_SMP
+ RTEMS_STATIC_ASSERT(
+ offsetof( Context_Control, is_executing )
+ == ARM_CONTEXT_CONTROL_IS_EXECUTING_OFFSET,
+ ARM_CONTEXT_CONTROL_IS_EXECUTING_OFFSET
+ );
+#endif
+
RTEMS_STATIC_ASSERT(
sizeof( CPU_Exception_frame ) == ARM_EXCEPTION_FRAME_SIZE,
ARM_EXCEPTION_FRAME_SIZE
@@ -93,6 +101,10 @@ void _CPU_Context_Initialize(
the_context->thread_id = (uint32_t) tls_area;
#endif
+#ifdef RTEMS_SMP
+ the_context->is_executing = false;
+#endif
+
if ( tls_area != NULL ) {
_TLS_TCB_at_area_begin_initialize( tls_area );
}
diff --git a/cpukit/score/cpu/arm/cpu_asm.S b/cpukit/score/cpu/arm/cpu_asm.S
index bae7207f2c..f2c4afe39e 100644
--- a/cpukit/score/cpu/arm/cpu_asm.S
+++ b/cpukit/score/cpu/arm/cpu_asm.S
@@ -67,12 +67,32 @@ DEFINE_FUNCTION_ARM(_CPU_Context_switch)
str r3, [r0, #ARM_CONTEXT_CONTROL_THREAD_ID_OFFSET]
#endif
+#ifdef RTEMS_SMP
+ /* Indicate that this context is no longer executing */
+ dmb
+ mov r3, #0
+ strb r3, [r0, #ARM_CONTEXT_CONTROL_IS_EXECUTING_OFFSET]
+#endif
+
/* Start restoring context */
_restore:
#ifdef ARM_MULTILIB_HAS_LOAD_STORE_EXCLUSIVE
clrex
#endif
+#ifdef RTEMS_SMP
+ /* Wait for context to stop execution if necessary */
+1:
+ ldrb r3, [r1, #ARM_CONTEXT_CONTROL_IS_EXECUTING_OFFSET]
+ cmp r3, #0
+ bne 1b
+
+ /* Indicate that this context is executing */
+ dmb
+ mov r3, #1
+ strb r3, [r1, #ARM_CONTEXT_CONTROL_IS_EXECUTING_OFFSET]
+#endif
+
#ifdef ARM_MULTILIB_HAS_THREAD_ID_REGISTER
ldr r3, [r1, #ARM_CONTEXT_CONTROL_THREAD_ID_OFFSET]
mcr p15, 0, r3, c13, c0, 3
diff --git a/cpukit/score/cpu/arm/rtems/score/cpu.h b/cpukit/score/cpu/arm/rtems/score/cpu.h
index cb9dc7c409..dc57a78a67 100644
--- a/cpukit/score/cpu/arm/rtems/score/cpu.h
+++ b/cpukit/score/cpu/arm/rtems/score/cpu.h
@@ -216,6 +216,14 @@
#define ARM_CONTEXT_CONTROL_D8_OFFSET 48
#endif
+#ifdef RTEMS_SMP
+ #ifdef ARM_MULTILIB_VFP_D32
+ #define ARM_CONTEXT_CONTROL_IS_EXECUTING_OFFSET 112
+ #else
+ #define ARM_CONTEXT_CONTROL_IS_EXECUTING_OFFSET 48
+ #endif
+#endif
+
#define ARM_EXCEPTION_FRAME_SIZE 76
#define ARM_EXCEPTION_FRAME_REGISTER_SP_OFFSET 52
@@ -280,6 +288,9 @@ typedef struct {
uint64_t register_d14;
uint64_t register_d15;
#endif
+#ifdef RTEMS_SMP
+ volatile bool is_executing;
+#endif
} Context_Control;
typedef struct {
@@ -410,6 +421,11 @@ void _CPU_Context_Initialize(
#define _CPU_Context_Get_SP( _context ) \
(_context)->register_sp
+#ifdef RTEMS_SMP
+ #define _CPU_Context_Get_is_executing( _context ) \
+ (_context)->is_executing
+#endif
+
#define _CPU_Context_Restart_self( _the_context ) \
_CPU_Context_restore( (_the_context) );
diff --git a/cpukit/score/cpu/i386/cpu.c b/cpukit/score/cpu/i386/cpu.c
index ba7501a246..38b84e6750 100644
--- a/cpukit/score/cpu/i386/cpu.c
+++ b/cpukit/score/cpu/i386/cpu.c
@@ -26,6 +26,24 @@
#include <rtems/bspIo.h>
#include <rtems/score/thread.h>
+#define I386_ASSERT_OFFSET(field, off) \
+ RTEMS_STATIC_ASSERT( \
+ offsetof(Context_Control, field) \
+ == I386_CONTEXT_CONTROL_ ## off ## _OFFSET, \
+ Context_Control_ ## field \
+ )
+
+I386_ASSERT_OFFSET(eflags, EFLAGS);
+I386_ASSERT_OFFSET(esp, ESP);
+I386_ASSERT_OFFSET(ebp, EBP);
+I386_ASSERT_OFFSET(ebx, EBX);
+I386_ASSERT_OFFSET(esi, ESI);
+I386_ASSERT_OFFSET(edi, EDI);
+
+#ifdef RTEMS_SMP
+ I386_ASSERT_OFFSET(is_executing, IS_EXECUTING);
+#endif
+
void _CPU_Initialize(void)
{
#if CPU_HARDWARE_FP
diff --git a/cpukit/score/cpu/i386/cpu_asm.S b/cpukit/score/cpu/i386/cpu_asm.S
index 73a4c143b4..cc08312f33 100644
--- a/cpukit/score/cpu/i386/cpu_asm.S
+++ b/cpukit/score/cpu/i386/cpu_asm.S
@@ -26,13 +26,12 @@
* Format of i386 Register structure
*/
-.set REG_EFLAGS, 0
-.set REG_ESP, REG_EFLAGS + 4
-.set REG_EBP, REG_ESP + 4
-.set REG_EBX, REG_EBP + 4
-.set REG_ESI, REG_EBX + 4
-.set REG_EDI, REG_ESI + 4
-.set SIZE_REGS, REG_EDI + 4
+.set REG_EFLAGS, I386_CONTEXT_CONTROL_EFLAGS_OFFSET
+.set REG_ESP, I386_CONTEXT_CONTROL_ESP_OFFSET
+.set REG_EBP, I386_CONTEXT_CONTROL_EBP_OFFSET
+.set REG_EBX, I386_CONTEXT_CONTROL_EBX_OFFSET
+.set REG_ESI, I386_CONTEXT_CONTROL_ESI_OFFSET
+.set REG_EDI, I386_CONTEXT_CONTROL_EDI_OFFSET
BEGIN_CODE
@@ -58,9 +57,25 @@ SYM (_CPU_Context_switch):
movl esi,REG_ESI(eax) /* save source register */
movl edi,REG_EDI(eax) /* save destination register */
+#ifdef RTEMS_SMP
+ /* Indicate that this context is no longer executing */
+ movb $0, I386_CONTEXT_CONTROL_IS_EXECUTING_OFFSET(eax)
+#endif
+
movl HEIRCONTEXT_ARG(esp),eax /* eax = heir threads context */
restore:
+#ifdef RTEMS_SMP
+ /* Wait for context to stop execution if necessary */
+1:
+ movb I386_CONTEXT_CONTROL_IS_EXECUTING_OFFSET(eax), bl
+ testb bl, bl
+ jne 1b
+
+ /* Indicate that this context is executing */
+ movb $1, I386_CONTEXT_CONTROL_IS_EXECUTING_OFFSET(eax)
+#endif
+
pushl REG_EFLAGS(eax) /* push eflags */
popf /* restore eflags */
movl REG_ESP(eax),esp /* restore stack pointer */
diff --git a/cpukit/score/cpu/i386/rtems/score/cpu.h b/cpukit/score/cpu/i386/rtems/score/cpu.h
index a9957cbe62..ba731b0666 100644
--- a/cpukit/score/cpu/i386/rtems/score/cpu.h
+++ b/cpukit/score/cpu/i386/rtems/score/cpu.h
@@ -128,6 +128,17 @@ extern "C" {
#define CPU_PER_CPU_CONTROL_SIZE 0
+#define I386_CONTEXT_CONTROL_EFLAGS_OFFSET 0
+#define I386_CONTEXT_CONTROL_ESP_OFFSET 4
+#define I386_CONTEXT_CONTROL_EBP_OFFSET 8
+#define I386_CONTEXT_CONTROL_EBX_OFFSET 12
+#define I386_CONTEXT_CONTROL_ESI_OFFSET 16
+#define I386_CONTEXT_CONTROL_EDI_OFFSET 20
+
+#ifdef RTEMS_SMP
+ #define I386_CONTEXT_CONTROL_IS_EXECUTING_OFFSET 24
+#endif
+
/* structures */
#ifndef ASM
@@ -147,11 +158,19 @@ typedef struct {
uint32_t ebx; /* extended bx register */
uint32_t esi; /* extended source index register */
uint32_t edi; /* extended destination index flags register */
+#ifdef RTEMS_SMP
+ volatile bool is_executing;
+#endif
} Context_Control;
#define _CPU_Context_Get_SP( _context ) \
(_context)->esp
+#ifdef RTEMS_SMP
+ #define _CPU_Context_Get_is_executing( _context ) \
+ (_context)->is_executing
+#endif
+
/*
* FP context save area for the i387 numeric coprocessors.
*/
@@ -435,6 +454,13 @@ uint32_t _CPU_ISR_Get_level( void );
*/
+#ifdef RTEMS_SMP
+ #define _I386_Context_Initialize_is_executing( _the_context ) \
+ (_the_context)->is_executing = false
+#else
+ #define _I386_Context_Initialize_is_executing( _the_context )
+#endif
+
#define _CPU_Context_Initialize( _the_context, _stack_base, _size, \
_isr, _entry_point, _is_fp, _tls_area ) \
do { \
@@ -449,6 +475,7 @@ uint32_t _CPU_ISR_Get_level( void );
*((proc_ptr *)(_stack)) = (_entry_point); \
(_the_context)->ebp = (void *) 0; \
(_the_context)->esp = (void *) _stack; \
+ _I386_Context_Initialize_is_executing( _the_context ); \
} while (0)
#define _CPU_Context_Restart_self( _the_context ) \
diff --git a/cpukit/score/cpu/no_cpu/rtems/score/cpu.h b/cpukit/score/cpu/no_cpu/rtems/score/cpu.h
index fbf207ad80..739a6a8a42 100644
--- a/cpukit/score/cpu/no_cpu/rtems/score/cpu.h
+++ b/cpukit/score/cpu/no_cpu/rtems/score/cpu.h
@@ -574,6 +574,18 @@ typedef struct {
* is the stack pointer.
*/
uint32_t stack_pointer;
+
+#ifdef RTEMS_SMP
+ /**
+ * @brief On SMP configurations the thread context must contain a boolean
+ * indicator if this context is executing on a processor.
+ *
+ * This field must be updated during a context switch. The context switch
+ * to the heir must wait until the heir context indicates that it is no
+ * longer executing on a processor.
+ */
+ volatile bool is_executing;
+#endif
} Context_Control;
/**
@@ -1582,6 +1594,12 @@ register struct Per_CPU_Control *_CPU_Per_CPU_current asm( "rX" );
{
__asm__ volatile ( "" : : : "memory" );
}
+
+ /**
+ * @brief Macro to return the is executing field of the thread context.
+ */
+ #define _CPU_Context_Get_is_executing( _context ) \
+ ( ( _context )->is_executing )
#endif
#ifdef __cplusplus
diff --git a/cpukit/score/cpu/powerpc/cpu.c b/cpukit/score/cpu/powerpc/cpu.c
index 3c699f9366..53b4eaa247 100644
--- a/cpukit/score/cpu/powerpc/cpu.c
+++ b/cpukit/score/cpu/powerpc/cpu.c
@@ -53,6 +53,10 @@ PPC_ASSERT_OFFSET(gpr30, GPR30);
PPC_ASSERT_OFFSET(gpr31, GPR31);
PPC_ASSERT_OFFSET(gpr2, GPR2);
+#ifdef RTEMS_SMP
+ PPC_ASSERT_OFFSET(is_executing, IS_EXECUTING);
+#endif
+
RTEMS_STATIC_ASSERT(
sizeof(Context_Control) % PPC_DEFAULT_CACHE_LINE_SIZE == 0,
ppc_context_size
diff --git a/cpukit/score/cpu/powerpc/rtems/score/cpu.h b/cpukit/score/cpu/powerpc/rtems/score/cpu.h
index 3a51b3112b..18a6770788 100644
--- a/cpukit/score/cpu/powerpc/rtems/score/cpu.h
+++ b/cpukit/score/cpu/powerpc/rtems/score/cpu.h
@@ -302,6 +302,9 @@ typedef struct {
PPC_GPR_TYPE gpr30;
PPC_GPR_TYPE gpr31;
uint32_t gpr2;
+ #ifdef RTEMS_SMP
+ volatile bool is_executing;
+ #endif
#ifdef __ALTIVEC__
/*
* 12 non-volatile vector registers, cache-aligned area for vscr/vrsave
@@ -327,7 +330,7 @@ typedef struct {
];
} Context_Control;
-static inline ppc_context *ppc_get_context( Context_Control *context )
+static inline ppc_context *ppc_get_context( const Context_Control *context )
{
uintptr_t clsz = PPC_DEFAULT_CACHE_LINE_SIZE;
uintptr_t mask = clsz - 1;
@@ -338,6 +341,11 @@ static inline ppc_context *ppc_get_context( Context_Control *context )
#define _CPU_Context_Get_SP( _context ) \
ppc_get_context(_context)->gpr1
+
+#ifdef RTEMS_SMP
+ #define _CPU_Context_Get_is_executing( _context ) \
+ ppc_get_context(_context)->is_executing
+#endif
#endif /* ASM */
#define PPC_CONTEXT_OFFSET_GPR1 32
@@ -368,6 +376,10 @@ static inline ppc_context *ppc_get_context( Context_Control *context )
#define PPC_CONTEXT_OFFSET_GPR31 PPC_CONTEXT_GPR_OFFSET( 31 )
#define PPC_CONTEXT_OFFSET_GPR2 PPC_CONTEXT_GPR_OFFSET( 32 )
+#ifdef RTEMS_SMP
+ #define PPC_CONTEXT_OFFSET_IS_EXECUTING (PPC_CONTEXT_GPR_OFFSET( 32 ) + 4)
+#endif
+
#ifndef ASM
typedef struct {
/* The ABIs (PowerOpen/SVR4/EABI) only require saving f14-f31 over
diff --git a/cpukit/score/cpu/sparc/cpu.c b/cpukit/score/cpu/sparc/cpu.c
index 6c124db4d2..d05c511162 100644
--- a/cpukit/score/cpu/sparc/cpu.c
+++ b/cpukit/score/cpu/sparc/cpu.c
@@ -67,6 +67,10 @@ SPARC_ASSERT_OFFSET(o7, O7);
SPARC_ASSERT_OFFSET(psr, PSR);
SPARC_ASSERT_OFFSET(isr_dispatch_disable, ISR_DISPATCH_DISABLE_STACK);
+#if defined(RTEMS_SMP)
+SPARC_ASSERT_OFFSET(is_executing, SPARC_CONTEXT_CONTROL_IS_EXECUTING);
+#endif
+
/*
* This initializes the set of opcodes placed in each trap
* table entry. The routine which installs a handler is responsible
@@ -326,6 +330,10 @@ void _CPU_Context_Initialize(
*/
the_context->isr_dispatch_disable = 0;
+#if defined(RTEMS_SMP)
+ the_context->is_executing = false;
+#endif
+
if ( tls_area != NULL ) {
void *tcb = _TLS_TCB_after_TLS_block_initialize( tls_area );
diff --git a/cpukit/score/cpu/sparc/rtems/score/cpu.h b/cpukit/score/cpu/sparc/rtems/score/cpu.h
index 50da44cf4b..7bcdbd9b37 100644
--- a/cpukit/score/cpu/sparc/rtems/score/cpu.h
+++ b/cpukit/score/cpu/sparc/rtems/score/cpu.h
@@ -473,6 +473,10 @@ typedef struct {
* SPARC CPU models at high interrupt rates.
*/
uint32_t isr_dispatch_disable;
+
+#if defined(RTEMS_SMP)
+ volatile bool is_executing;
+#endif
} Context_Control;
/**
@@ -483,6 +487,11 @@ typedef struct {
#define _CPU_Context_Get_SP( _context ) \
(_context)->o6_sp
+#ifdef RTEMS_SMP
+ #define _CPU_Context_Get_is_executing( _context ) \
+ (_context)->is_executing
+#endif
+
#endif /* ASM */
/*
@@ -538,6 +547,10 @@ typedef struct {
/** This macro defines an offset into the context for use in assembly. */
#define ISR_DISPATCH_DISABLE_STACK_OFFSET 0x54
+#if defined(RTEMS_SMP)
+ #define SPARC_CONTEXT_CONTROL_IS_EXECUTING_OFFSET 0x58
+#endif
+
/** This defines the size of the context area for use in assembly. */
#define CONTEXT_CONTROL_SIZE 0x68
diff --git a/cpukit/score/include/rtems/score/percpu.h b/cpukit/score/include/rtems/score/percpu.h
index 7f063eafb8..e232674c30 100644
--- a/cpukit/score/include/rtems/score/percpu.h
+++ b/cpukit/score/include/rtems/score/percpu.h
@@ -56,6 +56,8 @@ extern "C" {
typedef struct Thread_Control_struct Thread_Control;
#endif
+struct Scheduler_Context;
+
/**
* @defgroup PerCPU RTEMS Per CPU Information
*
@@ -268,13 +270,46 @@ typedef struct Per_CPU_Control {
*/
volatile uint32_t thread_dispatch_disable_level;
- /** This is set to true when this CPU needs to run the dispatcher. */
+ /**
+ * @brief This is set to true when this processor needs to run the
+ * dispatcher.
+ *
+ * It is volatile since interrupts may alter this flag.
+ *
+ * This field is not protected by a lock. There are two writers after
+ * multitasking start. The scheduler owning this processor sets this
+ * indicator to true, after it updated the heir field. This processor sets
+ * this indicator to false, before it reads the heir. This field is used in
+ * combination with the heir field.
+ *
+ * @see _Thread_Get_heir_and_make_it_executing().
+ */
volatile bool dispatch_necessary;
- /** This is the thread executing on this CPU. */
+ /**
+ * @brief This is the thread executing on this processor.
+ *
+ * This field is not protected by a lock. The only writer is this processor.
+ *
+ * On SMP configurations a thread may be registered as executing on more than
+ * one processor in case a thread migration is in progress. On SMP
+ * configurations use _Thread_Is_executing_on_a_processor() to figure out if
+ * a thread context is executing on a processor.
+ */
Thread_Control *executing;
- /** This is the heir thread for this this CPU. */
+ /**
+ * @brief This is the heir thread for this processor.
+ *
+ * This field is not protected by a lock. The only writer after multitasking
+ * start is the scheduler owning this processor. This processor will set the
+ * dispatch necessary indicator to false, before it reads the heir. This
+ * field is used in combination with the dispatch necessary indicator.
+ *
+ * A thread can be a heir on at most one processor in the system.
+ *
+ * @see _Thread_Get_heir_and_make_it_executing().
+ */
Thread_Control *heir;
/** This is the time of the last context switch on this CPU. */
@@ -282,11 +317,12 @@ typedef struct Per_CPU_Control {
#if defined( RTEMS_SMP )
/**
- * @brief This lock protects the dispatch_necessary, executing, heir and
- * message fields.
+ * @brief This lock protects some parts of the low-level thread dispatching.
*
* We must use a ticket lock here since we cannot transport a local context
* through the context switch.
+ *
+ * @see _Thread_Dispatch().
*/
SMP_ticket_lock_Control Lock;
@@ -310,6 +346,11 @@ typedef struct Per_CPU_Control {
Atomic_Ulong message;
/**
+ * @brief The scheduler context of the scheduler owning this processor.
+ */
+ const struct Scheduler_Context *scheduler_context;
+
+ /**
* @brief Indicates the current state of the CPU.
*
* This field is protected by the _Per_CPU_State_lock lock.
diff --git a/cpukit/score/include/rtems/score/scheduler.h b/cpukit/score/include/rtems/score/scheduler.h
index 9002ef85d9..2a1c4338a6 100644
--- a/cpukit/score/include/rtems/score/scheduler.h
+++ b/cpukit/score/include/rtems/score/scheduler.h
@@ -148,7 +148,7 @@ typedef struct {
* The scheduler context of a particular scheduler implementation must place
* this structure at the begin of its context structure.
*/
-typedef struct {
+typedef struct Scheduler_Context {
#if defined(RTEMS_SMP)
/**
* @brief Count of processors owned by this scheduler instance.
diff --git a/cpukit/score/include/rtems/score/schedulerimpl.h b/cpukit/score/include/rtems/score/schedulerimpl.h
index 6fad4e2190..cb73d5e586 100644
--- a/cpukit/score/include/rtems/score/schedulerimpl.h
+++ b/cpukit/score/include/rtems/score/schedulerimpl.h
@@ -390,29 +390,25 @@ RTEMS_INLINE_ROUTINE const Scheduler_Control *_Scheduler_Get(
#endif
}
-RTEMS_INLINE_ROUTINE bool _Scheduler_Set(
+RTEMS_INLINE_ROUTINE void _Scheduler_Set(
const Scheduler_Control *scheduler,
Thread_Control *the_thread
)
{
- bool ok;
-
- if ( _States_Is_dormant( the_thread->current_state ) ) {
#if defined(RTEMS_SMP)
+ const Scheduler_Control *current_scheduler = _Scheduler_Get( the_thread );
+
+ if ( current_scheduler != scheduler ) {
+ _Thread_Set_state( the_thread, STATES_MIGRATING );
_Scheduler_Free( _Scheduler_Get( the_thread ), the_thread );
the_thread->scheduler = scheduler;
_Scheduler_Allocate( scheduler, the_thread );
_Scheduler_Update( scheduler, the_thread );
+ _Thread_Clear_state( the_thread, STATES_MIGRATING );
+ }
#else
- (void) scheduler;
+ (void) scheduler;
#endif
-
- ok = true;
- } else {
- ok = false;
- }
-
- return ok;
}
RTEMS_INLINE_ROUTINE bool _Scheduler_default_Set_affinity_body(
@@ -448,9 +444,7 @@ RTEMS_INLINE_ROUTINE bool _Scheduler_default_Set_affinity_body(
ok = ok && !CPU_ISSET_S( (int) cpu_index, cpusetsize, cpuset );
}
- if ( ok ) {
- ok = _Scheduler_Set( scheduler, the_thread );
- }
+ _Scheduler_Set( scheduler, the_thread );
return ok;
}
diff --git a/cpukit/score/include/rtems/score/schedulersmp.h b/cpukit/score/include/rtems/score/schedulersmp.h
index 8f5a390a26..778a1fb832 100644
--- a/cpukit/score/include/rtems/score/schedulersmp.h
+++ b/cpukit/score/include/rtems/score/schedulersmp.h
@@ -24,9 +24,7 @@
#define _RTEMS_SCORE_SCHEDULERSMP_H
#include <rtems/score/chain.h>
-#include <rtems/score/percpu.h>
-#include <rtems/score/prioritybitmap.h>
-#include <rtems/score/thread.h>
+#include <rtems/score/scheduler.h>
#ifdef __cplusplus
extern "C" {
diff --git a/cpukit/score/include/rtems/score/schedulersmpimpl.h b/cpukit/score/include/rtems/score/schedulersmpimpl.h
index c3e11e6dc6..69222c28f8 100644
--- a/cpukit/score/include/rtems/score/schedulersmpimpl.h
+++ b/cpukit/score/include/rtems/score/schedulersmpimpl.h
@@ -24,9 +24,9 @@
#define _RTEMS_SCORE_SCHEDULERSMPIMPL_H
#include <rtems/score/schedulersmp.h>
-#include <rtems/score/schedulersimpleimpl.h>
+#include <rtems/score/assert.h>
#include <rtems/score/chainimpl.h>
-#include <rtems/score/scheduler.h>
+#include <rtems/score/schedulersimpleimpl.h>
#ifdef __cplusplus
extern "C" {
@@ -64,47 +64,74 @@ static inline void _Scheduler_SMP_Initialize(
_Chain_Initialize_empty( &self->Scheduled );
}
+static inline bool _Scheduler_SMP_Is_processor_owned_by_us(
+ const Scheduler_SMP_Context *self,
+ const Per_CPU_Control *cpu
+)
+{
+ return cpu->scheduler_context == &self->Base;
+}
+
+static inline void _Scheduler_SMP_Update_heir(
+ Per_CPU_Control *cpu_self,
+ Per_CPU_Control *cpu_for_heir,
+ Thread_Control *heir
+)
+{
+ cpu_for_heir->heir = heir;
+
+ /*
+ * It is critical that we first update the heir and then the dispatch
+ * necessary so that _Thread_Get_heir_and_make_it_executing() cannot miss an
+ * update.
+ */
+ _Atomic_Fence( ATOMIC_ORDER_SEQ_CST );
+
+ /*
+ * Only update the dispatch necessary indicator if not already set to
+ * avoid superfluous inter-processor interrupts.
+ */
+ if ( !cpu_for_heir->dispatch_necessary ) {
+ cpu_for_heir->dispatch_necessary = true;
+
+ if ( cpu_for_heir != cpu_self ) {
+ _Per_CPU_Send_interrupt( cpu_for_heir );
+ }
+ }
+}
+
static inline void _Scheduler_SMP_Allocate_processor(
+ Scheduler_SMP_Context *self,
Thread_Control *scheduled,
Thread_Control *victim
)
{
Per_CPU_Control *cpu_of_scheduled = _Thread_Get_CPU( scheduled );
Per_CPU_Control *cpu_of_victim = _Thread_Get_CPU( victim );
+ Per_CPU_Control *cpu_self = _Per_CPU_Get();
Thread_Control *heir;
scheduled->is_scheduled = true;
victim->is_scheduled = false;
- _Per_CPU_Acquire( cpu_of_scheduled );
+ _Assert( _ISR_Get_level() != 0 );
- if ( scheduled->is_executing ) {
- heir = cpu_of_scheduled->heir;
- cpu_of_scheduled->heir = scheduled;
+ if ( _Thread_Is_executing_on_a_processor( scheduled ) ) {
+ if ( _Scheduler_SMP_Is_processor_owned_by_us( self, cpu_of_scheduled ) ) {
+ heir = cpu_of_scheduled->heir;
+ _Scheduler_SMP_Update_heir( cpu_self, cpu_of_scheduled, scheduled );
+ } else {
+ /* We have to force a migration to our processor set */
+ _Assert( scheduled->debug_real_cpu->heir != scheduled );
+ heir = scheduled;
+ }
} else {
heir = scheduled;
}
- _Per_CPU_Release( cpu_of_scheduled );
-
if ( heir != victim ) {
- const Per_CPU_Control *cpu_of_executing = _Per_CPU_Get();
-
_Thread_Set_CPU( heir, cpu_of_victim );
-
- cpu_of_victim->heir = heir;
-
- /*
- * It is critical that we first update the heir and then the dispatch
- * necessary so that _Thread_Dispatch() cannot miss an update.
- */
- _Atomic_Fence( ATOMIC_ORDER_RELEASE );
-
- cpu_of_victim->dispatch_necessary = true;
-
- if ( cpu_of_victim != cpu_of_executing ) {
- _Per_CPU_Send_interrupt( cpu_of_victim );
- }
+ _Scheduler_SMP_Update_heir( cpu_self, cpu_of_victim, heir );
}
}
@@ -148,7 +175,7 @@ static inline void _Scheduler_SMP_Enqueue_ordered(
highest_ready != NULL
&& !( *order )( &thread->Object.Node, &highest_ready->Object.Node )
) {
- _Scheduler_SMP_Allocate_processor( highest_ready, thread );
+ _Scheduler_SMP_Allocate_processor( self, highest_ready, thread );
( *insert_ready )( self, thread );
( *move_from_ready_to_scheduled )( self, highest_ready );
@@ -168,7 +195,7 @@ static inline void _Scheduler_SMP_Enqueue_ordered(
lowest_scheduled != NULL
&& ( *order )( &thread->Object.Node, &lowest_scheduled->Object.Node )
) {
- _Scheduler_SMP_Allocate_processor( thread, lowest_scheduled );
+ _Scheduler_SMP_Allocate_processor( self, thread, lowest_scheduled );
( *insert_scheduled )( self, thread );
( *move_from_scheduled_to_ready )( self, lowest_scheduled );
@@ -187,7 +214,7 @@ static inline void _Scheduler_SMP_Schedule_highest_ready(
{
Thread_Control *highest_ready = ( *get_highest_ready )( self );
- _Scheduler_SMP_Allocate_processor( highest_ready, victim );
+ _Scheduler_SMP_Allocate_processor( self, highest_ready, victim );
( *move_from_ready_to_scheduled )( self, highest_ready );
}
diff --git a/cpukit/score/include/rtems/score/statesimpl.h b/cpukit/score/include/rtems/score/statesimpl.h
index 842d108236..0dbf0db71e 100644
--- a/cpukit/score/include/rtems/score/statesimpl.h
+++ b/cpukit/score/include/rtems/score/statesimpl.h
@@ -82,6 +82,8 @@ extern "C" {
#define STATES_WAITING_FOR_TERMINATION 0x100000
/** This macro corresponds to a task being a zombie. */
#define STATES_ZOMBIE 0x200000
+/** This macro corresponds to a task migration to another scheduler. */
+#define STATES_MIGRATING 0x400000
/** This macro corresponds to a task which is in an interruptible
* blocking state.
diff --git a/cpukit/score/include/rtems/score/thread.h b/cpukit/score/include/rtems/score/thread.h
index 90df3a74dc..248ae96850 100644
--- a/cpukit/score/include/rtems/score/thread.h
+++ b/cpukit/score/include/rtems/score/thread.h
@@ -504,20 +504,6 @@ struct Thread_Control_struct {
bool is_in_the_air;
/**
- * @brief This field is true if the thread is executing.
- *
- * A thread is executing if it executes on a processor. An executing thread
- * executes on exactly one processor. There are exactly processor count
- * executing threads in the system. An executing thread may have a heir
- * thread and thread dispatching is necessary. On SMP a thread dispatch on a
- * remote processor needs help from an inter-processor interrupt, thus it
- * will take some time to complete the state change. A lot of things can
- * happen in the meantime. This field is volatile since it is polled in
- * _Thread_Kill_zombies().
- */
- volatile bool is_executing;
-
- /**
* @brief The scheduler of this thread.
*/
const struct Scheduler_Control *scheduler;
@@ -548,7 +534,18 @@ struct Thread_Control_struct {
void *scheduler_info;
#ifdef RTEMS_SMP
+ /**
+ * @brief The processor assigned by the scheduler.
+ */
Per_CPU_Control *cpu;
+
+#ifdef RTEMS_DEBUG
+ /**
+ * @brief The processor on which this thread executed the last time or is
+ * executing.
+ */
+ Per_CPU_Control *debug_real_cpu;
+#endif
#endif
/** This field contains information about the starting state of
diff --git a/cpukit/score/include/rtems/score/threadimpl.h b/cpukit/score/include/rtems/score/threadimpl.h
index 4efc85d8f1..2be5cc56fa 100644
--- a/cpukit/score/include/rtems/score/threadimpl.h
+++ b/cpukit/score/include/rtems/score/threadimpl.h
@@ -454,6 +454,22 @@ RTEMS_INLINE_ROUTINE bool _Thread_Is_executing (
return ( the_thread == _Thread_Executing );
}
+#if defined(RTEMS_SMP)
+/**
+ * @brief Returns @true in case the thread executes currently on some processor
+ * in the system, otherwise @a false.
+ *
+ * Do not confuse this with _Thread_Is_executing() which checks only the
+ * current processor.
+ */
+RTEMS_INLINE_ROUTINE bool _Thread_Is_executing_on_a_processor(
+ const Thread_Control *the_thread
+)
+{
+ return _CPU_Context_Get_is_executing( &the_thread->Registers );
+}
+#endif
+
/**
* This function returns true if the_thread is the heir
* thread, and false otherwise.
@@ -491,7 +507,7 @@ RTEMS_INLINE_ROUTINE void _Thread_Restart_self( Thread_Control *executing )
_Giant_Release();
- _Per_CPU_ISR_disable_and_acquire( _Per_CPU_Get(), level );
+ _ISR_Disable_without_giant( level );
( void ) level;
#endif
@@ -590,7 +606,7 @@ RTEMS_INLINE_ROUTINE void _Thread_Request_dispatch_if_executing(
)
{
#if defined(RTEMS_SMP)
- if ( thread->is_executing ) {
+ if ( _Thread_Is_executing_on_a_processor( thread ) ) {
const Per_CPU_Control *cpu_of_executing = _Per_CPU_Get();
Per_CPU_Control *cpu_of_thread = _Thread_Get_CPU( thread );
@@ -611,7 +627,7 @@ RTEMS_INLINE_ROUTINE void _Thread_Signal_notification( Thread_Control *thread )
_Thread_Dispatch_necessary = true;
} else {
#if defined(RTEMS_SMP)
- if ( thread->is_executing ) {
+ if ( _Thread_Is_executing_on_a_processor( thread ) ) {
const Per_CPU_Control *cpu_of_executing = _Per_CPU_Get();
Per_CPU_Control *cpu_of_thread = _Thread_Get_CPU( thread );
@@ -624,6 +640,39 @@ RTEMS_INLINE_ROUTINE void _Thread_Signal_notification( Thread_Control *thread )
}
}
+/**
+ * @brief Gets the heir of the processor and makes it executing.
+ *
+ * The thread dispatch necessary indicator is cleared as a side-effect.
+ *
+ * @return The heir thread.
+ *
+ * @see _Thread_Dispatch(), _Thread_Start_multitasking() and
+ * _Scheduler_SMP_Update_heir().
+ */
+RTEMS_INLINE_ROUTINE Thread_Control *_Thread_Get_heir_and_make_it_executing(
+ Per_CPU_Control *cpu_self
+)
+{
+ Thread_Control *heir;
+
+ cpu_self->dispatch_necessary = false;
+
+#if defined( RTEMS_SMP )
+ /*
+ * It is critical that we first update the dispatch necessary and then the
+ * read the heir so that we don't miss an update by
+ * _Scheduler_SMP_Update_heir().
+ */
+ _Atomic_Fence( ATOMIC_ORDER_SEQ_CST );
+#endif
+
+ heir = cpu_self->heir;
+ cpu_self->executing = heir;
+
+ return heir;
+}
+
RTEMS_INLINE_ROUTINE void _Thread_Update_cpu_time_used(
Thread_Control *executing,
Timestamp_Control *time_of_last_context_switch
@@ -736,6 +785,19 @@ RTEMS_INLINE_ROUTINE bool _Thread_Is_life_changing(
return ( life_state & THREAD_LIFE_RESTARTING_TERMINTING ) != 0;
}
+RTEMS_INLINE_ROUTINE void _Thread_Debug_set_real_processor(
+ Thread_Control *the_thread,
+ Per_CPU_Control *cpu
+)
+{
+#if defined(RTEMS_SMP) && defined(RTEMS_DEBUG)
+ the_thread->debug_real_cpu = cpu;
+#else
+ (void) the_thread;
+ (void) cpu;
+#endif
+}
+
#if !defined(__DYNAMIC_REENT__)
/**
* This routine returns the C library re-enterant pointer.
diff --git a/cpukit/score/include/rtems/score/userextimpl.h b/cpukit/score/include/rtems/score/userextimpl.h
index 04808e1f17..19055f976b 100644
--- a/cpukit/score/include/rtems/score/userextimpl.h
+++ b/cpukit/score/include/rtems/score/userextimpl.h
@@ -216,13 +216,21 @@ static inline void _User_extensions_Thread_switch(
const Chain_Node *tail = _Chain_Immutable_tail( chain );
const Chain_Node *node = _Chain_Immutable_first( chain );
- while ( node != tail ) {
- const User_extensions_Switch_control *extension =
- (const User_extensions_Switch_control *) node;
+ if ( node != tail ) {
+ Per_CPU_Control *cpu_self = _Per_CPU_Get();
- (*extension->thread_switch)( executing, heir );
+ _Per_CPU_Acquire( cpu_self );
- node = _Chain_Immutable_next( node );
+ while ( node != tail ) {
+ const User_extensions_Switch_control *extension =
+ (const User_extensions_Switch_control *) node;
+
+ (*extension->thread_switch)( executing, heir );
+
+ node = _Chain_Immutable_next( node );
+ }
+
+ _Per_CPU_Release( cpu_self );
}
}
diff --git a/cpukit/score/src/smp.c b/cpukit/score/src/smp.c
index 519b152d87..2f86c6e175 100644
--- a/cpukit/score/src/smp.c
+++ b/cpukit/score/src/smp.c
@@ -58,7 +58,10 @@ static void _SMP_Start_processors( uint32_t cpu_count )
cpu->started = started;
if ( started ) {
- ++assignment->scheduler->context->processor_count;
+ Scheduler_Context *scheduler_context = assignment->scheduler->context;
+
+ ++scheduler_context->processor_count;
+ cpu->scheduler_context = scheduler_context;
}
}
}
diff --git a/cpukit/score/src/threaddispatch.c b/cpukit/score/src/threaddispatch.c
index f1c6cfd103..982bbc476a 100644
--- a/cpukit/score/src/threaddispatch.c
+++ b/cpukit/score/src/threaddispatch.c
@@ -64,10 +64,14 @@ void _Thread_Dispatch( void )
{
Per_CPU_Control *cpu_self;
Thread_Control *executing;
- Thread_Control *heir;
ISR_Level level;
#if defined( RTEMS_SMP )
+ /*
+ * On SMP the complete context switch must be atomic with respect to one
+ * processor. See also _Thread_Handler() since _Context_switch() may branch
+ * to this function.
+ */
_ISR_Disable_without_giant( level );
#endif
@@ -76,45 +80,21 @@ void _Thread_Dispatch( void )
_Profiling_Thread_dispatch_disable( cpu_self, 0 );
cpu_self->thread_dispatch_disable_level = 1;
-#if defined( RTEMS_SMP )
- _ISR_Enable_without_giant( level );
-#endif
-
/*
* Now determine if we need to perform a dispatch on the current CPU.
*/
executing = cpu_self->executing;
- _Per_CPU_ISR_disable_and_acquire( cpu_self, level );
-#if defined( RTEMS_SMP )
- /*
- * On SMP the complete context switch must be atomic with respect to one
- * processor. The scheduler must obtain the per-CPU lock to check if a
- * thread is executing and to update the heir. This ensures that a thread
- * cannot execute on more than one processor at a time. See also
- * _Thread_Handler() since _Context_switch() may branch to this function.
- */
- if ( cpu_self->dispatch_necessary ) {
-#else
- while ( cpu_self->dispatch_necessary ) {
-#endif
- cpu_self->dispatch_necessary = false;
-#if defined( RTEMS_SMP )
- /*
- * It is critical that we first update the dispatch necessary and then the
- * read the heir so that we don't miss an update by
- * _Scheduler_SMP_Allocate_processor().
- */
- _Atomic_Fence( ATOMIC_ORDER_SEQ_CST );
+#if !defined( RTEMS_SMP )
+ _ISR_Disable( level );
#endif
- heir = cpu_self->heir;
- cpu_self->executing = heir;
-
#if defined( RTEMS_SMP )
- executing->is_executing = false;
- heir->is_executing = true;
+ if ( cpu_self->dispatch_necessary ) {
+#else
+ while ( cpu_self->dispatch_necessary ) {
#endif
+ Thread_Control *heir = _Thread_Get_heir_and_make_it_executing( cpu_self );
/*
* When the heir and executing are the same, then we are being
@@ -207,6 +187,8 @@ void _Thread_Dispatch( void )
*/
cpu_self = _Per_CPU_Get();
+ _Thread_Debug_set_real_processor( executing, cpu_self );
+
#if !defined( RTEMS_SMP )
_ISR_Disable( level );
#endif
@@ -217,7 +199,7 @@ post_switch:
cpu_self->thread_dispatch_disable_level = 0;
_Profiling_Thread_dispatch_enable( cpu_self, 0 );
- _Per_CPU_Release_and_ISR_enable( cpu_self, level );
+ _ISR_Enable_without_giant( level );
_Thread_Run_post_switch_actions( executing );
}
diff --git a/cpukit/score/src/threadhandler.c b/cpukit/score/src/threadhandler.c
index 229e74f937..5f6623f11f 100644
--- a/cpukit/score/src/threadhandler.c
+++ b/cpukit/score/src/threadhandler.c
@@ -153,11 +153,11 @@ void _Thread_Handler( void )
_Assert( cpu_self->thread_dispatch_disable_level == 1 );
_Assert( _ISR_Get_level() != 0 );
+ _Thread_Debug_set_real_processor( executing, cpu_self );
+
cpu_self->thread_dispatch_disable_level = 0;
_Profiling_Thread_dispatch_enable( cpu_self, 0 );
- _Per_CPU_Release( cpu_self );
-
level = executing->Start.isr_level;
_ISR_Set_level( level);
diff --git a/cpukit/score/src/threadinitialize.c b/cpukit/score/src/threadinitialize.c
index fb3d6c8589..1a03b0d320 100644
--- a/cpukit/score/src/threadinitialize.c
+++ b/cpukit/score/src/threadinitialize.c
@@ -52,6 +52,7 @@ bool _Thread_Initialize(
bool extension_status;
size_t i;
bool scheduler_allocated = false;
+ Per_CPU_Control *cpu = _Per_CPU_Get_by_index( 0 );
#if defined( RTEMS_SMP )
if ( rtems_configuration_is_smp_enabled() && !is_preemptible ) {
@@ -182,12 +183,13 @@ bool _Thread_Initialize(
#if defined(RTEMS_SMP)
the_thread->is_scheduled = false;
the_thread->is_in_the_air = false;
- the_thread->is_executing = false;
the_thread->scheduler = scheduler;
#endif
+ _Thread_Debug_set_real_processor( the_thread, cpu );
+
/* Initialize the CPU for the non-SMP schedulers */
- _Thread_Set_CPU( the_thread, _Per_CPU_Get_by_index( 0 ) );
+ _Thread_Set_CPU( the_thread, cpu );
the_thread->current_state = STATES_DORMANT;
the_thread->Wait.queue = NULL;
diff --git a/cpukit/score/src/threadrestart.c b/cpukit/score/src/threadrestart.c
index 422ee33a6d..9cf2a85165 100644
--- a/cpukit/score/src/threadrestart.c
+++ b/cpukit/score/src/threadrestart.c
@@ -107,7 +107,7 @@ static void _Thread_Wait_for_execution_stop( Thread_Control *the_thread )
* in case the thread termination sequence is interrupted by a slow interrupt
* service on a remote processor.
*/
- while (the_thread->is_executing) {
+ while ( _Thread_Is_executing_on_a_processor( the_thread ) ) {
/* Wait */
}
#else
diff --git a/cpukit/score/src/threadstartmultitasking.c b/cpukit/score/src/threadstartmultitasking.c
index 78a438f6d8..c1c8725eae 100644
--- a/cpukit/score/src/threadstartmultitasking.c
+++ b/cpukit/score/src/threadstartmultitasking.c
@@ -30,22 +30,12 @@ void _Thread_Start_multitasking( void )
/*
* Threads begin execution in the _Thread_Handler() function. This
- * function will set the thread dispatch disable level to zero and calls
- * _Per_CPU_Release().
+ * function will set the thread dispatch disable level to zero.
*/
- _Per_CPU_Acquire( cpu_self );
cpu_self->thread_dispatch_disable_level = 1;
#endif
- heir = cpu_self->heir;
-
-#if defined(RTEMS_SMP)
- cpu_self->executing->is_executing = false;
- heir->is_executing = true;
-#endif
-
- cpu_self->dispatch_necessary = false;
- cpu_self->executing = heir;
+ heir = _Thread_Get_heir_and_make_it_executing( cpu_self );
/*
* Get the init task(s) running.
diff --git a/doc/user/smp.t b/doc/user/smp.t
index 0ad21f5662..0751abae44 100644
--- a/doc/user/smp.t
+++ b/doc/user/smp.t
@@ -211,6 +211,52 @@ affinity. Although the behavior is scheduler specific, if the scheduler
does not support affinity, it is likely to ignore all attempts to set
affinity.
+@subsection Task Migration
+
+@cindex task migration
+@cindex thread migration
+
+With more than one processor in the system tasks can migrate from one processor
+to another. There are three reasons why tasks migrate in RTEMS.
+
+@itemize @bullet
+@item The scheduler changes explicitly via @code{rtems_task_set_scheduler()} or
+similar directives.
+@item The task resumes execution after a blocking operation. On a priority
+based scheduler it will evict the lowest priority task currently assigned to a
+processor in the processor set managed by the scheduler instance.
+@item The task moves temporarily to another scheduler instance due to locking
+protocols like @cite{Migratory Priority Inheritance} or the
+@cite{Multiprocessor Resource Sharing Protocol}.
+@end itemize
+
+Task migration should be avoided so that the working set of a task can stay on
+the most local cache level.
+
+The current implementation of task migration in RTEMS has some implications
+with respect to the interrupt latency. It is crucial to preserve the system
+invariant that a task can execute on at most one processor in the system at a
+time. This is accomplished with a boolean indicator in the task context. The
+processor architecture specific low-level task context switch code will mark
+that a task context is no longer executing and waits that the heir context
+stopped execution before it restores the heir context and resumes execution of
+the heir task. So there is one point in time in which a processor is without a
+task. This is essential to avoid cyclic dependencies in case multiple tasks
+migrate at once. Otherwise some supervising entity is necessary to prevent
+life-locks. Such a global supervisor would lead to scalability problems so
+this approach is not used. Currently the thread dispatch is performed with
+interrupts disabled. So in case the heir task is currently executing on
+another processor then this prolongs the time of disabled interrupts since one
+processor has to wait for another processor to make progress.
+
+It is difficult to avoid this issue with the interrupt latency since interrupts
+normally store the context of the interrupted task on its stack. In case a
+task is marked as not executing we must not use its task stack to store such an
+interrupt context. We cannot use the heir stack before it stopped execution on
+another processor. So if we enable interrupts during this transition we have
+to provide an alternative task independent stack for this time frame. This
+issue needs further investigation.
+
@subsection Critical Section Techniques and SMP
As discussed earlier, SMP systems have opportunities for true parallelism
diff --git a/testsuites/smptests/Makefile.am b/testsuites/smptests/Makefile.am
index d82503a17c..36fb156f3f 100644
--- a/testsuites/smptests/Makefile.am
+++ b/testsuites/smptests/Makefile.am
@@ -22,6 +22,7 @@ SUBDIRS += smpipi01
SUBDIRS += smpload01
SUBDIRS += smplock01
SUBDIRS += smpmigration01
+SUBDIRS += smpmigration02
SUBDIRS += smpscheduler01
SUBDIRS += smpscheduler02
SUBDIRS += smpsignal01
diff --git a/testsuites/smptests/configure.ac b/testsuites/smptests/configure.ac
index 27f7f542b3..0b9b4c6313 100644
--- a/testsuites/smptests/configure.ac
+++ b/testsuites/smptests/configure.ac
@@ -77,6 +77,7 @@ smpipi01/Makefile
smpload01/Makefile
smplock01/Makefile
smpmigration01/Makefile
+smpmigration02/Makefile
smppsxaffinity01/Makefile
smppsxaffinity02/Makefile
smppsxsignal01/Makefile
diff --git a/testsuites/smptests/smpmigration02/Makefile.am b/testsuites/smptests/smpmigration02/Makefile.am
new file mode 100644
index 0000000000..8dcd8ad68f
--- /dev/null
+++ b/testsuites/smptests/smpmigration02/Makefile.am
@@ -0,0 +1,19 @@
+rtems_tests_PROGRAMS = smpmigration02
+smpmigration02_SOURCES = init.c
+
+dist_rtems_tests_DATA = smpmigration02.scn smpmigration02.doc
+
+include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
+include $(top_srcdir)/../automake/compile.am
+include $(top_srcdir)/../automake/leaf.am
+
+AM_CPPFLAGS += -I$(top_srcdir)/../support/include
+
+LINK_OBJS = $(smpmigration02_OBJECTS)
+LINK_LIBS = $(smpmigration02_LDLIBS)
+
+smpmigration02$(EXEEXT): $(smpmigration02_OBJECTS) $(smpmigration02_DEPENDENCIES)
+ @rm -f smpmigration02$(EXEEXT)
+ $(make-exe)
+
+include $(top_srcdir)/../automake/local.am
diff --git a/testsuites/smptests/smpmigration02/init.c b/testsuites/smptests/smpmigration02/init.c
new file mode 100644
index 0000000000..7cf4651663
--- /dev/null
+++ b/testsuites/smptests/smpmigration02/init.c
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2014 embedded brains GmbH. All rights reserved.
+ *
+ * embedded brains GmbH
+ * Dornierstr. 4
+ * 82178 Puchheim
+ * Germany
+ * <rtems@embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.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[] = "SMPMIGRATION 2";
+
+#define CPU_COUNT 32
+
+#define TASK_COUNT (CPU_COUNT + 1)
+
+#define PRIO_LOW 3
+
+#define PRIO_HIGH 2
+
+typedef struct {
+ uint32_t value;
+ uint32_t cache_line_separation[31];
+} test_counter;
+
+typedef struct {
+ test_counter counters[TASK_COUNT];
+ rtems_id scheduler_ids[CPU_COUNT];
+ rtems_id task_ids[TASK_COUNT];
+} test_context;
+
+static test_context test_instance;
+
+static void task(rtems_task_argument arg)
+{
+ test_context *ctx = &test_instance;
+ rtems_status_code sc;
+ uint32_t cpu_count = rtems_get_processor_count();
+ uint32_t cpu_index = rtems_get_current_processor();
+
+ while (true) {
+ cpu_index = (cpu_index + 1) % cpu_count;
+
+ sc = rtems_task_set_scheduler(RTEMS_SELF, ctx->scheduler_ids[cpu_index]);
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+
+ ++ctx->counters[arg].value;
+
+ rtems_test_assert(cpu_index == rtems_get_current_processor());
+ }
+}
+
+static void test(void)
+{
+ test_context *ctx = &test_instance;
+ rtems_status_code sc;
+ uint32_t cpu_count = rtems_get_processor_count();
+ uint32_t cpu_index;
+ uint32_t task_count = cpu_count + 1;
+ uint32_t task_index;
+
+ for (cpu_index = 0; cpu_index < cpu_count; ++cpu_index) {
+ sc = rtems_scheduler_ident(cpu_index, &ctx->scheduler_ids[cpu_index]);
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+ }
+
+ for (task_index = 0; task_index < task_count; ++task_index) {
+ rtems_id task_id;
+
+ sc = rtems_task_create(
+ rtems_build_name('T', 'A', 'S', 'K'),
+ task_index > 0 ? PRIO_LOW : PRIO_HIGH,
+ RTEMS_MINIMUM_STACK_SIZE,
+ RTEMS_DEFAULT_MODES,
+ RTEMS_DEFAULT_ATTRIBUTES,
+ &task_id
+ );
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+
+ sc = rtems_task_set_scheduler(task_id, ctx->scheduler_ids[task_index % cpu_count]);
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+
+ sc = rtems_task_start(task_id, task, task_index);
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+
+ ctx->task_ids[task_index] = task_id;
+ }
+
+ sc = rtems_task_wake_after(30 * rtems_clock_get_ticks_per_second());
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+
+ for (task_index = 0; task_index < task_count; ++task_index) {
+ printf(
+ "task %" PRIu32 " counter: %" PRIu32 "\n",
+ task_index,
+ ctx->counters[task_index].value
+ );
+
+ sc = rtems_task_delete(ctx->task_ids[task_index]);
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+ }
+}
+
+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_SCHEDULER_SIMPLE_SMP
+
+#include <rtems/scheduler.h>
+
+RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(0);
+RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(1);
+RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(2);
+RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(3);
+RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(4);
+RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(5);
+RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(6);
+RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(7);
+RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(8);
+RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(9);
+RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(10);
+RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(11);
+RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(12);
+RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(13);
+RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(14);
+RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(15);
+RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(16);
+RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(17);
+RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(18);
+RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(19);
+RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(20);
+RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(21);
+RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(22);
+RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(23);
+RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(24);
+RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(25);
+RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(26);
+RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(27);
+RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(28);
+RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(29);
+RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(30);
+RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(31);
+
+#define CONFIGURE_SCHEDULER_CONTROLS \
+ RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(0, 0), \
+ RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(1, 1), \
+ RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(2, 2), \
+ RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(3, 3), \
+ RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(4, 4), \
+ RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(5, 5), \
+ RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(6, 6), \
+ RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(7, 7), \
+ RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(8, 8), \
+ RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(9, 9), \
+ RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(10, 10), \
+ RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(11, 11), \
+ RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(12, 12), \
+ RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(13, 13), \
+ RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(14, 14), \
+ RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(15, 15), \
+ RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(16, 16), \
+ RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(17, 17), \
+ RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(18, 18), \
+ RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(19, 19), \
+ RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(20, 20), \
+ RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(21, 21), \
+ RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(22, 22), \
+ RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(23, 23), \
+ RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(24, 24), \
+ RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(25, 25), \
+ RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(26, 26), \
+ RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(27, 27), \
+ RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(28, 28), \
+ RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(29, 29), \
+ RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(30, 30), \
+ RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(31, 31)
+
+#define CONFIGURE_SMP_SCHEDULER_ASSIGNMENTS \
+ RTEMS_SCHEDULER_ASSIGN(0, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
+ RTEMS_SCHEDULER_ASSIGN(1, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
+ RTEMS_SCHEDULER_ASSIGN(2, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
+ RTEMS_SCHEDULER_ASSIGN(3, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
+ RTEMS_SCHEDULER_ASSIGN(4, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
+ RTEMS_SCHEDULER_ASSIGN(5, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
+ RTEMS_SCHEDULER_ASSIGN(6, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
+ RTEMS_SCHEDULER_ASSIGN(7, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
+ RTEMS_SCHEDULER_ASSIGN(8, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
+ RTEMS_SCHEDULER_ASSIGN(9, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
+ RTEMS_SCHEDULER_ASSIGN(10, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
+ RTEMS_SCHEDULER_ASSIGN(11, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
+ RTEMS_SCHEDULER_ASSIGN(12, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
+ RTEMS_SCHEDULER_ASSIGN(13, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
+ RTEMS_SCHEDULER_ASSIGN(14, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
+ RTEMS_SCHEDULER_ASSIGN(15, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
+ RTEMS_SCHEDULER_ASSIGN(16, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
+ RTEMS_SCHEDULER_ASSIGN(17, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
+ RTEMS_SCHEDULER_ASSIGN(18, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
+ RTEMS_SCHEDULER_ASSIGN(19, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
+ RTEMS_SCHEDULER_ASSIGN(20, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
+ RTEMS_SCHEDULER_ASSIGN(21, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
+ RTEMS_SCHEDULER_ASSIGN(22, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
+ RTEMS_SCHEDULER_ASSIGN(23, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
+ RTEMS_SCHEDULER_ASSIGN(24, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
+ RTEMS_SCHEDULER_ASSIGN(25, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
+ RTEMS_SCHEDULER_ASSIGN(26, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
+ RTEMS_SCHEDULER_ASSIGN(27, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
+ RTEMS_SCHEDULER_ASSIGN(28, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
+ RTEMS_SCHEDULER_ASSIGN(29, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
+ RTEMS_SCHEDULER_ASSIGN(30, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
+ RTEMS_SCHEDULER_ASSIGN(31, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL)
+
+#define CONFIGURE_MAXIMUM_TASKS (1 + TASK_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/smpmigration02/smpmigration02.doc b/testsuites/smptests/smpmigration02/smpmigration02.doc
new file mode 100644
index 0000000000..bfae205f5d
--- /dev/null
+++ b/testsuites/smptests/smpmigration02/smpmigration02.doc
@@ -0,0 +1,12 @@
+This file describes the directives and concepts tested by this test set.
+
+test set name: smpmigration02
+
+directives:
+
+ - _Scheduler_SMP_Allocate_processor()
+ - _CPU_Context_switch()
+
+concepts:
+
+ - Ensure that forced thread migration works.
diff --git a/testsuites/smptests/smpmigration02/smpmigration02.scn b/testsuites/smptests/smpmigration02/smpmigration02.scn
new file mode 100644
index 0000000000..c436e19a67
--- /dev/null
+++ b/testsuites/smptests/smpmigration02/smpmigration02.scn
@@ -0,0 +1,7 @@
+*** BEGIN OF TEST SMPMIGRATION 2 ***
+task 0 counter: 1137459
+task 1 counter: 1136714
+task 2 counter: 1136713
+task 3 counter: 1136712
+task 4 counter: 1136711
+*** END OF TEST SMPMIGRATION 2 ***
diff --git a/testsuites/smptests/smpscheduler02/init.c b/testsuites/smptests/smpscheduler02/init.c
index 1e6b6d5925..5bfff0e088 100644
--- a/testsuites/smptests/smpscheduler02/init.c
+++ b/testsuites/smptests/smpscheduler02/init.c
@@ -158,8 +158,8 @@ static void test(void)
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_task_set_scheduler(task_id, scheduler_b_id);
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
sc = rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT);
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
diff --git a/testsuites/smptests/smpswitchextension01/smpswitchextension01.scn b/testsuites/smptests/smpswitchextension01/smpswitchextension01.scn
index 9024fdb341..64b9b6e88d 100644
--- a/testsuites/smptests/smpswitchextension01/smpswitchextension01.scn
+++ b/testsuites/smptests/smpswitchextension01/smpswitchextension01.scn
@@ -1,13 +1,13 @@
-*** TEST SMPSWITCHEXTENSION 1 ***
+*** BEGIN OF TEST SMPSWITCHEXTENSION 1 ***
toggler 0
- toggles 2146479
+ toggles 1555183
toggler 1
- toggles 2146477
+ toggles 1555182
extension 0
- context switches 2146478
+ context switches 1555185
extension 1
- context switches 2146481
+ context switches 1244705
extension 2
- context switches 2146482
-extension switches 718121
+ context switches 1554688
+extension switches 311649
*** END OF TEST SMPSWITCHEXTENSION 1 ***
diff --git a/testsuites/sptests/spscheduler01/init.c b/testsuites/sptests/spscheduler01/init.c
index 30ea4ce8f9..bcb656dbc1 100644
--- a/testsuites/sptests/spscheduler01/init.c
+++ b/testsuites/sptests/spscheduler01/init.c
@@ -81,10 +81,10 @@ 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);
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
sc = rtems_task_set_affinity(self_id, sizeof(cpuset), &cpuset);
- rtems_test_assert(sc == RTEMS_INVALID_NUMBER);
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
sc = rtems_task_set_affinity(task_id, sizeof(cpuset), &cpuset);
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
@@ -163,7 +163,7 @@ static void test_task_get_set_scheduler(void)
rtems_test_assert(sc == RTEMS_INVALID_ID);
sc = rtems_task_set_scheduler(self_id, scheduler_id);
- rtems_test_assert(sc == RTEMS_INCORRECT_STATE);
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
sc = rtems_task_create(
rtems_build_name('T', 'A', 'S', 'K'),
@@ -188,7 +188,7 @@ static void test_task_get_set_scheduler(void)
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
sc = rtems_task_set_scheduler(task_id, scheduler_id);
- rtems_test_assert(sc == RTEMS_INCORRECT_STATE);
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
sc = rtems_task_delete(task_id);
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
diff --git a/testsuites/tmtests/tm26/task1.c b/testsuites/tmtests/tm26/task1.c
index 6b2572ef9e..96859404ac 100644
--- a/testsuites/tmtests/tm26/task1.c
+++ b/testsuites/tmtests/tm26/task1.c
@@ -146,8 +146,6 @@ static void thread_disable_dispatch( void )
self_cpu = _Per_CPU_Get();
self_cpu->thread_dispatch_disable_level = 1;
-
- _Per_CPU_Acquire( self_cpu );
#else
_Thread_Disable_dispatch();
#endif