summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2021-11-10 11:11:32 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2021-11-11 16:51:34 +0100
commit6d351281757d36c59d0399bf5dda3f443ae26de3 (patch)
treea195fb0c89ce0edc5633ea99637b9c9de4ba5788
parentmodules: Update rtems (diff)
downloadrtems-central-6d351281757d36c59d0399bf5dda3f443ae26de3.tar.bz2
spec: Improve processor removal specification
-rw-r--r--spec/rtems/scheduler/req/remove-processor.yml906
-rw-r--r--spec/score/sched/smp/req/remove-last-processor-helping.yml17
-rw-r--r--spec/score/sched/smp/val/smp.yml112
3 files changed, 801 insertions, 234 deletions
diff --git a/spec/rtems/scheduler/req/remove-processor.yml b/spec/rtems/scheduler/req/remove-processor.yml
index aa3223c4..c7be0d2a 100644
--- a/spec/rtems/scheduler/req/remove-processor.yml
+++ b/spec/rtems/scheduler/req/remove-processor.yml
@@ -39,11 +39,27 @@ post-conditions:
states:
- name: 'Yes'
test-code: |
- T_eq_sz( ctx->scheduler_log.header.recorded, 1 );
- T_eq_int(
- ctx->scheduler_log.events[ 0 ].operation,
- T_SCHEDULER_REMOVE_PROCESSOR
- );
+ if ( ctx->home && ctx->helping ) {
+ T_eq_sz( ctx->scheduler_log.header.recorded, 3 );
+ T_eq_int(
+ ctx->scheduler_log.events[ 0 ].operation,
+ T_SCHEDULER_REMOVE_PROCESSOR
+ );
+ T_eq_int(
+ ctx->scheduler_log.events[ 1 ].operation,
+ T_SCHEDULER_ASK_FOR_HELP
+ );
+ T_eq_int(
+ ctx->scheduler_log.events[ 2 ].operation,
+ T_SCHEDULER_ASK_FOR_HELP
+ );
+ } else {
+ T_eq_sz( ctx->scheduler_log.header.recorded, 1 );
+ T_eq_int(
+ ctx->scheduler_log.events[ 0 ].operation,
+ T_SCHEDULER_REMOVE_PROCESSOR
+ );
+ }
text: |
The processor specified by the ${../if/remove-processor:/params[1]/name}
parameter shall be removed from the scheduler specified by the
@@ -58,44 +74,6 @@ post-conditions:
test-epilogue: null
test-prologue: null
pre-conditions:
-- name: CPUState
- states:
- - name: Idle
- test-code: |
- ctx->scheduler_id = ctx->scheduler_b_id;
- ctx->cpu_to_remove = 1;
- text: |
- While the processor associated with the
- ${../if/remove-processor:/params[1]/name} parameter is owned by the
- scheduler specified by the ${../if/remove-processor:/params[0]/name}
- parameter, while no task exists which uses the scheduler as its
- ${/glossary/scheduler-home:/term} and the affinity set of this task would
- require the processor specified by the
- ${../if/remove-processor:/params[1]/name} parameter.
- - name: InUse
- test-code: |
- /* Set by prologue */
- text: |
- While the processor associated with the
- ${../if/remove-processor:/params[1]/name} parameter is owned by the
- scheduler specified by the ${../if/remove-processor:/params[0]/name}
- parameter, while the scheduler is used by at least one task as its
- ${/glossary/scheduler-home:/term} and the affinity set of this task
- requires the processor specified by the
- ${../if/remove-processor:/params[1]/name} parameter.
- - name: NotOwned
- test-code: |
- ctx->scheduler_id = ctx->scheduler_a_id;
- ctx->cpu_to_remove = 1;
- text: |
- While the processor associated with the
- ${../if/remove-processor:/params[1]/name} parameter is not owned by the
- scheduler specified by the ${../if/remove-processor:/params[0]/name}
- parameter.
- test-epilogue: null
- test-prologue: |
- ctx->scheduler_id = ctx->scheduler_a_id;
- ctx->cpu_to_remove = 0;
- name: Id
states:
- name: Invalid
@@ -106,7 +84,7 @@ pre-conditions:
associated with a scheduler.
- name: Scheduler
test-code: |
- ctx->id = ctx->scheduler_id;
+ ctx->id = SCHEDULER_A_ID;
text: |
While the ${../if/remove-processor:/params[0]/name} parameter is
associated with a scheduler.
@@ -116,7 +94,7 @@ pre-conditions:
states:
- name: Valid
test-code: |
- ctx->cpu_index = ctx->cpu_to_remove;
+ ctx->cpu_index = 0;
text: |
While the ${../if/remove-processor:/params[1]/name} parameter is less than
the configured processor maximum.
@@ -128,6 +106,136 @@ pre-conditions:
than or equal to the configured processor maximum.
test-epilogue: null
test-prologue: null
+- name: Owned
+ states:
+ - name: 'Yes'
+ test-code: |
+ ctx->owned = true;
+ text: |
+ While the processor specified by the
+ ${../if/remove-processor:/params[1]/name} parameter is owned by the
+ scheduler specified by the ${../if/remove-processor:/params[0]/name}
+ parameter.
+ - name: 'No'
+ test-code: |
+ ctx->owned = false;
+ text: |
+ While the processor specified by the
+ ${../if/remove-processor:/params[1]/name} parameter is not owned by the
+ scheduler specified by the ${../if/remove-processor:/params[0]/name}
+ parameter.
+ test-epilogue: null
+ test-prologue: null
+- name: Last
+ states:
+ - name: 'Yes'
+ test-code: |
+ ctx->last = true;
+ text: |
+ While the processor specified by the
+ ${../if/remove-processor:/params[1]/name} parameter is the last processor
+ owned by the scheduler specified by the
+ ${../if/remove-processor:/params[0]/name} parameter.
+ - name: 'No'
+ test-code: |
+ ctx->last = false;
+ text: |
+ While the processor specified by the
+ ${../if/remove-processor:/params[1]/name} parameter is not the last
+ processor owned by the scheduler specified by the
+ ${../if/remove-processor:/params[0]/name} parameter.
+ test-epilogue: null
+ test-prologue: null
+- name: Home
+ states:
+ - name: 'Yes'
+ test-code: |
+ ctx->home = true;
+ text: |
+ While at least one non-idle task exists which uses the scheduler
+ specified by the ${../if/remove-processor:/params[0]/name} parameter as
+ its ${/glossary/scheduler-home:/term}.
+ - name: 'No'
+ test-code: |
+ ctx->home = false;
+ text: |
+ While no non-idle task exists which uses the scheduler specified by the
+ ${../if/remove-processor:/params[0]/name} parameter as its
+ ${/glossary/scheduler-home:/term}.
+ test-epilogue: null
+ test-prologue: null
+- name: RequiredByAffinity
+ states:
+ - name: 'Yes'
+ test-code: |
+ ctx->required_by_affinity = true;
+ text: |
+ While at least one non-idle task which uses the scheduler specified by
+ the ${../if/remove-processor:/params[0]/name} parameter as its
+ ${/glossary/scheduler-home:/term} exists those processor affinity set
+ requires the processor specified by the
+ ${../if/remove-processor:/params[1]/name} parameter.
+ - name: 'No'
+ test-code: |
+ ctx->required_by_affinity = false;
+ text: |
+ While no non-idle task which uses the scheduler specified by the
+ ${../if/remove-processor:/params[0]/name} parameter as its
+ ${/glossary/scheduler-home:/term} exists those processor affinity set
+ requires the processor specified by the
+ ${../if/remove-processor:/params[1]/name} parameter.
+ test-epilogue: null
+ test-prologue: null
+- name: UsedBy
+ states:
+ - name: Idle
+ test-code: |
+ ctx->idle = true;
+ ctx->task = false;
+ ctx->helping = false;
+ text: |
+ While the processor specified by the
+ ${../if/remove-processor:/params[1]/name} parameter is used by an idle
+ task.
+ - name: Task
+ test-code: |
+ ctx->idle = false;
+ ctx->task = true;
+ ctx->helping = false;
+ text: |
+ While the processor specified by the
+ ${../if/remove-processor:/params[1]/name} parameter is used by a task
+ task which uses the scheduler specified by the
+ ${../if/remove-processor:/params[0]/name} parameter as its
+ ${/glossary/scheduler-home:/term}.
+ - name: TaskIdle
+ test-code: |
+ ctx->idle = true;
+ ctx->task = true;
+ ctx->helping = false;
+ text: |
+ While the processor specified by the
+ ${../if/remove-processor:/params[1]/name} parameter is used by an idle
+ task on behalf of a task task which uses the scheduler specified by the
+ ${../if/remove-processor:/params[0]/name} parameter as its
+ ${/glossary/scheduler-home:/term}.
+ - name: Helping
+ test-code: |
+ if ( !ctx->last && rtems_scheduler_get_processor_maximum() < 3 ) {
+ ${.:skip}
+ } else {
+ ctx->idle = false;
+ ctx->task = false;
+ ctx->helping = true;
+ }
+ text: |
+ While the processor specified by the
+ ${../if/remove-processor:/params[1]/name} parameter is used by a task
+ task which uses the scheduler specified by the
+ ${../if/remove-processor:/params[0]/name} parameter as a
+ ${/glossary/scheduler-helping:/term}.
+ test-epilogue: null
+ test-prologue: null
rationale: null
references: []
requirement-type: functional
@@ -135,56 +243,212 @@ skip-reasons:
OnlyOneCPU: |
Where the system is build with SMP support disabled, the system has exactly
one processor and there is no processor available to remove from a
- scheduler.
+ scheduler. In addition, the scheduler helping protocol is not available.
+ NoHomeNoTaskUser: |
+ The processor can only be used by a task if a task uses the scheduler as
+ its home scheduler.
+ LastIsRequired: |
+ The last processor is required by a task which uses the scheduler as its
+ home scheduler.
test-action: |
- T_scheduler_log *log;
+ if (
+ ctx->id == INVALID_ID ||
+ ctx->cpu_index == rtems_configuration_get_maximum_processors() ||
+ ( ctx->owned && ctx->last && ctx->home && ctx->required_by_affinity &&
+ ( ctx->task || ctx->idle ) )
+ ) {
+ DoRemoveProcessor( ctx );
+ } else {
+ #if defined(RTEMS_SMP)
+ if ( ctx->owned && !ctx->home && ctx->helping ) {
+ RemoveWithHelpingOnly( ctx );
+ } else {
+ if ( ctx->owned ) {
+ rtems_id worker_a;
+ rtems_id worker_b;
- log = T_scheduler_record_2( &ctx->scheduler_log );
- T_null( log );
+ worker_a = ctx->worker_id[ WORKER_A ];
+ worker_b = ctx->worker_id[ WORKER_B ];
- ctx->status = rtems_scheduler_remove_processor( ctx->id, ctx->cpu_index );
+ ctx->cpu_index = 1;
- log = T_scheduler_record( NULL );
- T_eq_ptr( &log->header, &ctx->scheduler_log.header );
-test-brief: null
-test-cleanup: |
- #if defined(RTEMS_SMP)
- if ( ctx->status == RTEMS_SUCCESSFUL ) {
- rtems_status_code sc;
+ if ( ctx->last ) {
+ ctx->id = SCHEDULER_B_ID;
+ } else {
+ RemoveProcessor( SCHEDULER_B_ID, 1 );
+ AddProcessor( SCHEDULER_A_ID, 1 );
+ }
- sc = rtems_scheduler_add_processor(
- ctx->scheduler_id,
- ctx->cpu_to_remove
- );
- T_rsc_success( sc );
- }
+ if ( ctx->home ) {
+ SetScheduler( worker_a, ctx->id, PRIO_LOW );
+
+ if ( ctx->required_by_affinity ) {
+ SetAffinityOne( worker_a, 1 );
+ } else {
+ SetAffinityAll( worker_a );
+ }
+ }
+
+ if ( ctx->idle ) {
+ if ( ctx->task ) {
+ SendAndSync( ctx, WORKER_A, EVENT_STICKY_OBTAIN );
+ SuspendTask( worker_a );
+ }
+ } else if ( ctx->task ) {
+ MakeBusy( ctx, WORKER_A );
+ } else if ( ctx->helping ) {
+ T_true( ctx->home );
+
+ if ( ctx->last ) {
+ SendEvents( worker_b, EVENT_OBTAIN );
+ SetPriority( worker_b, PRIO_LOW );
+ } else {
+ SetScheduler( worker_b, SCHEDULER_C_ID, PRIO_LOW );
+ SendAndSync( ctx, WORKER_B, EVENT_OBTAIN );
+ MakeBusyAndSync( ctx, WORKER_C );
+ }
+
+ SendAndSync( ctx, WORKER_A, EVENT_OBTAIN );
+ MakeBusy( ctx, WORKER_B );
+ WaitForBusy( ctx, WORKER_B );
+ }
+
+ DoRemoveProcessor( ctx );
+
+ if ( ctx->idle ) {
+ if ( ctx->task ) {
+ ResumeTask( worker_a );
+ SendAndSync( ctx, WORKER_A, EVENT_STICKY_RELEASE );
+ }
+ } else if ( ctx->task ) {
+ StopBusyAndWait( ctx, WORKER_A );
+ } else if ( ctx->helping ) {
+ StopBusy( ctx, WORKER_B );
+
+ if ( ctx->last ) {
+ SetPriority( worker_b, PRIO_HIGH );
+ SendEvents( worker_b, EVENT_RELEASE );
+ } else {
+ StopBusyAndWait( ctx, WORKER_C );
+ SendAndSync( ctx, WORKER_B, EVENT_RELEASE );
+ SetScheduler( worker_b, SCHEDULER_A_ID, PRIO_HIGH );
+ }
+
+ WaitForExecutionStop( worker_b );
+ SendAndSync( ctx, WORKER_A, EVENT_RELEASE );
+ }
+
+ SetAffinityAll( worker_a );
+ SetScheduler( worker_a, SCHEDULER_A_ID, PRIO_HIGH );
+
+ if ( !ctx->last ) {
+ RemoveProcessor( SCHEDULER_A_ID, 1 );
+ AddProcessor( SCHEDULER_B_ID, 1 );
+ }
+ } else {
+ ctx->id = SCHEDULER_B_ID;
+ DoRemoveProcessor( ctx );
+ }
+ }
+ #else
+ T_unreachable();
#endif
+ }
+test-brief: null
+test-cleanup: null
test-context:
- brief: |
- This member specifies the scheduler used to add the processor.
+ This member contains the runner identifier.
+ description: null
+ member: |
+ rtems_id runner_id
+- brief: |
+ This member contains the worker identifiers.
+ description: null
+ member: |
+ rtems_id worker_id[ WORKER_COUNT ]
+- brief: |
+ This member contains the mutex identifier.
+ description: null
+ member: |
+ rtems_id mutex_id
+- brief: |
+ This member contains the sticky mutex identifier.
+ description: null
+ member: |
+ rtems_id sticky_id
+- brief: |
+ This member contains the worker busy status.
+ description: null
+ member: |
+ volatile bool busy[ WORKER_COUNT ];
+- brief: |
+ This member contains the worker busy status.
+ description: null
+ member: |
+ volatile uint32_t busy_counter[ WORKER_COUNT ];
+- brief: |
+ This member contains the barrier to synchronize the runner and the workers.
+ description: null
+ member: |
+ SMP_barrier_Control barrier
+- brief: |
+ This member contains the call within ISR request.
+ description: null
+ member: |
+ CallWithinISRRequest request;
+- brief: |
+ This member provides the context to wrap thread queue operations.
+ description: null
+ member: |
+ WrapThreadQueueContext wrap_tq_ctx
+- brief: |
+ If this member is true, then the processor to remove shall be owned by the
+ scheduler.
+ description: null
+ member: |
+ bool owned
+- brief: |
+ If this member is true, then the processor to remove shall be the last
+ processor of the scheduler.
+ description: null
+ member: |
+ bool last
+- brief: |
+ If this member is true, then at least one non-idle task shall use the
+ scheduler as its home scheduler.
+ description: null
+ member: |
+ bool home
+- brief: |
+ If this member is true, then at least one non-idle task shall required the
+ processor to remove due to its affinity set.
description: null
member: |
- rtems_id scheduler_id
+ bool required_by_affinity
- brief: |
- This member contains the identifier of scheduler A.
+ If this member is true, then the processor to remove shall be used by an
+ idle task.
description: null
member: |
- rtems_id scheduler_a_id
+ bool idle
- brief: |
- This member contains the identifier of scheduler B.
+ If this member is true, then the processor to remove shall be used by a
+ task or on behalf of a task which uses the scheduler as its home scheduler.
description: null
member: |
- rtems_id scheduler_b_id
+ bool task
- brief: |
- This member specifies the processor to remove.
+ If this member is true, then the processor to remove shall be used by a
+ task which uses the scheduler as a helping scheduler.
description: null
member: |
- uint32_t cpu_to_remove
+ bool helping
- brief: |
This member provides the scheduler operation records.
description: null
member: |
- T_scheduler_log_2 scheduler_log;
+ T_scheduler_log_10 scheduler_log;
- brief: |
This member contains the return value of the
${../if/remove-processor:/name} call.
@@ -192,49 +456,347 @@ test-context:
member: |
rtems_status_code status
- brief: |
- This member specifies if the ${../if/remove-processor:/params[0]/name}
+ This member specifies the ${../if/remove-processor:/params[0]/name}
parameter value.
description: null
member: |
rtems_id id
- brief: |
- This member specifies if the ${../if/remove-processor:/params[1]/name}
+ This member specifies the ${../if/remove-processor:/params[1]/name}
parameter value.
description: null
member: |
uint32_t cpu_index
-test-context-support: null
+test-context-support: |
+ typedef enum {
+ WORKER_A,
+ WORKER_B,
+ WORKER_C,
+ WORKER_COUNT
+ } WorkerIndex;
test-description: null
test-header: null
test-includes:
- rtems.h
- rtems/test-scheduler.h
+- rtems/score/percpu.h
+- rtems/score/smpbarrier.h
test-local-includes:
- ts-config.h
- tx-support.h
-test-prepare: null
+test-prepare: |
+ ctx->status = RTEMS_NOT_IMPLEMENTED;
test-setup:
brief: null
code: |
- rtems_status_code sc;
+ #if defined(RTEMS_SMP)
+ rtems_status_code sc;
+ rtems_task_priority priority;
+
+ ctx->runner_id = rtems_task_self();
+ ctx->mutex_id = CreateMutex();
- sc = rtems_scheduler_ident(
- TEST_SCHEDULER_A_NAME,
- &ctx->scheduler_a_id
+ sc = rtems_semaphore_create(
+ rtems_build_name( 'S', 'T', 'K', 'Y' ),
+ 1,
+ RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY |
+ RTEMS_MULTIPROCESSOR_RESOURCE_SHARING,
+ PRIO_NORMAL,
+ &ctx->sticky_id
);
T_rsc_success( sc );
- #if defined(RTEMS_SMP)
- sc = rtems_scheduler_ident( TEST_SCHEDULER_B_NAME, &ctx->scheduler_b_id );
+ sc = rtems_semaphore_set_priority(
+ ctx->sticky_id,
+ SCHEDULER_B_ID,
+ PRIO_NORMAL,
+ &priority
+ );
T_rsc_success( sc );
- #else
- ctx->scheduler_b_id = INVALID_ID;
+
+ if ( rtems_scheduler_get_processor_maximum() >= 3 ) {
+ sc = rtems_semaphore_set_priority(
+ ctx->sticky_id,
+ SCHEDULER_C_ID,
+ PRIO_LOW,
+ &priority
+ );
+ T_rsc_success( sc );
+
+ ctx->worker_id[ WORKER_C ] = CreateTask( "WRKC", PRIO_NORMAL );
+ SetScheduler( ctx->worker_id[ WORKER_C ], SCHEDULER_C_ID, PRIO_NORMAL );
+ StartTask( ctx->worker_id[ WORKER_C ], WorkerC, ctx );
+
+ if ( rtems_scheduler_get_processor_maximum() >= 4 ) {
+ RemoveProcessor( SCHEDULER_C_ID, 3 );
+ }
+ }
+
+ SetSelfPriority( PRIO_NORMAL );
+ SetSelfAffinityOne( 0 );
+
+ ctx->worker_id[ WORKER_A ] = CreateTask( "WRKA", PRIO_HIGH );
+ StartTask( ctx->worker_id[ WORKER_A ], WorkerA, ctx );
+
+ ctx->worker_id[ WORKER_B ] = CreateTask( "WRKB", PRIO_HIGH );
+ StartTask( ctx->worker_id[ WORKER_B ], WorkerB, ctx );
+
+ WrapThreadQueueInitialize( &ctx->wrap_tq_ctx, RequestISR, ctx );
#endif
description: null
test-stop: null
-test-support: null
+test-support: |
+ typedef ${.:/test-context-type} Context;
+
+ static void DoRemoveProcessor( Context *ctx )
+ {
+ T_scheduler_log *log;
+
+ log = T_scheduler_record_10( &ctx->scheduler_log );
+ T_null( log );
+
+ ctx->status = rtems_scheduler_remove_processor( ctx->id, ctx->cpu_index );
+
+ log = T_scheduler_record( NULL );
+ T_eq_ptr( &log->header, &ctx->scheduler_log.header );
+
+ if ( ctx->status == RTEMS_SUCCESSFUL ) {
+ AddProcessor( ctx->id, ctx->cpu_index );
+ }
+ }
+
+ #if defined(RTEMS_SMP)
+ typedef enum {
+ EVENT_SYNC_RUNNER = RTEMS_EVENT_0,
+ EVENT_OBTAIN = RTEMS_EVENT_1,
+ EVENT_RELEASE = RTEMS_EVENT_2,
+ EVENT_STICKY_OBTAIN = RTEMS_EVENT_3,
+ EVENT_STICKY_RELEASE = RTEMS_EVENT_4,
+ EVENT_RESTART = RTEMS_EVENT_5,
+ EVENT_BUSY = RTEMS_EVENT_6,
+ EVENT_SYNC_RUNNER_LATE = RTEMS_EVENT_7
+ } Event;
+
+ static void Barriers( void *arg )
+ {
+ Context *ctx;
+ SMP_barrier_State barrier_state;
+
+ ctx = arg;
+ _SMP_barrier_State_initialize( &barrier_state );
+
+ /* A */
+ _SMP_barrier_Wait( &ctx->barrier, &barrier_state, 2 );
+
+ /* B */
+ _SMP_barrier_Wait( &ctx->barrier, &barrier_state, 2 );
+ }
+
+ static void RequestISR( void *arg )
+ {
+ Context *ctx;
+
+ ctx = arg;
+ ctx->request.handler = Barriers;
+ ctx->request.arg = ctx;
+ CallWithinISRSubmit( &ctx->request );
+ }
+
+ static void SendAndSync( Context *ctx, WorkerIndex worker, Event event )
+ {
+ SendEvents( ctx->worker_id[ worker ], EVENT_SYNC_RUNNER | event );
+ ReceiveAllEvents( EVENT_SYNC_RUNNER );
+ WaitForExecutionStop( ctx->worker_id[ worker ] );
+ }
+
+ static void MakeBusy( Context *ctx, WorkerIndex worker )
+ {
+ ctx->busy_counter[ worker ] = 0;
+ ctx->busy[ worker ] = true;
+ SendEvents( ctx->worker_id[ worker ], EVENT_BUSY );
+ }
+
+ static void MakeBusyAndSync( Context *ctx, WorkerIndex worker )
+ {
+ ctx->busy_counter[ worker ] = 0;
+ ctx->busy[ worker ] = true;
+ SendEvents( ctx->worker_id[ worker ], EVENT_SYNC_RUNNER | EVENT_BUSY );
+ ReceiveAllEvents( EVENT_SYNC_RUNNER );
+ }
+
+ static void StopBusy( Context *ctx, WorkerIndex worker )
+ {
+ ctx->busy[ worker ] = false;
+ }
+
+ static void StopBusyAndWait( Context *ctx, WorkerIndex worker )
+ {
+ StopBusy( ctx, worker );
+ WaitForExecutionStop( ctx->worker_id[ worker ] );
+ }
+
+ static void WaitForBusy( Context *ctx, WorkerIndex worker )
+ {
+ while ( ctx->busy_counter[ worker ] == 0 ) {
+ /* Wait */
+ }
+ }
+
+ static void RemoveWithHelpingOnly( Context *ctx )
+ {
+ SMP_barrier_State barrier_state;
+
+ /*
+ * Use the mutex and the worker to construct the removal of the last
+ * processor of a scheduler while a thread is scheduled.
+ */
+
+ _SMP_barrier_Control_initialize( &ctx->barrier );
+ _SMP_barrier_State_initialize( &barrier_state );
+
+ SetScheduler( ctx->worker_id[ WORKER_B ], SCHEDULER_B_ID, PRIO_NORMAL );
+
+ /* Let worker B help worker A */
+ SendEvents( ctx->worker_id[ WORKER_A ], EVENT_OBTAIN );
+ SendAndSync( ctx, WORKER_B, EVENT_OBTAIN );
+
+ /*
+ * Restart the worker B to withdraw the help offer and wait on barriers.
+ * Move worker B to scheduler A. Remove the processor while worker A is
+ * scheduled.
+ */
+
+ SendEvents( ctx->worker_id[ WORKER_A ], EVENT_RESTART );
+
+ /* A */
+ _SMP_barrier_Wait( &ctx->barrier, &barrier_state, 2 );
+
+ SetScheduler( ctx->worker_id[ WORKER_B ], SCHEDULER_A_ID, PRIO_HIGH );
+
+ ctx->id = SCHEDULER_B_ID;
+ ctx->cpu_index = 1;
+ DoRemoveProcessor( ctx );
+
+ /* B */
+ _SMP_barrier_Wait( &ctx->barrier, &barrier_state, 2 );
+
+ /* Clean up all used resources */
+ SetSelfPriority( PRIO_NORMAL );
+ SendEvents( ctx->worker_id[ WORKER_A ], EVENT_RELEASE );
+ T_busy(100000);
+ }
+
+ static void Worker( rtems_task_argument arg, WorkerIndex worker )
+ {
+ Context *ctx;
+
+ ctx = (Context *) arg;
+
+ while ( true ) {
+ rtems_event_set events;
+
+ events = ReceiveAnyEvents();
+
+ if ( ( events & EVENT_SYNC_RUNNER ) != 0 ) {
+ SendEvents( ctx->runner_id, EVENT_SYNC_RUNNER );
+ }
+
+ if ( ( events & EVENT_OBTAIN ) != 0 ) {
+ ObtainMutex( ctx->mutex_id );
+ }
+
+ if ( ( events & EVENT_RELEASE ) != 0 ) {
+ ReleaseMutex( ctx->mutex_id );
+ }
+
+ if ( ( events & EVENT_STICKY_OBTAIN ) != 0 ) {
+ ObtainMutex( ctx->sticky_id );
+ }
+
+ if ( ( events & EVENT_STICKY_RELEASE ) != 0 ) {
+ ReleaseMutex( ctx->sticky_id );
+ }
+
+ if ( ( events & EVENT_RESTART ) != 0 ) {
+ rtems_status_code sc;
+
+ T_eq_u32( rtems_scheduler_get_processor(), 0 );
+ SetPriority( ctx->runner_id, PRIO_VERY_HIGH );
+ T_eq_u32( rtems_scheduler_get_processor(), 1 );
+
+ if ( !ctx->last ) {
+ SetScheduler( ctx->worker_id[ WORKER_C ], SCHEDULER_A_ID, PRIO_LOW );
+ RemoveProcessor( SCHEDULER_C_ID, 2 );
+ AddProcessor( SCHEDULER_B_ID, 2 );
+ }
+
+ WrapThreadQueueExtract(
+ &ctx->wrap_tq_ctx,
+ GetThread( ctx->worker_id[ WORKER_B ] )
+ );
+
+ sc = rtems_task_restart(
+ ctx->worker_id[ WORKER_B ],
+ (rtems_task_argument) ctx
+ );
+ T_rsc_success( sc );
+
+ T_eq_u32( rtems_scheduler_get_processor(), 0 );
+
+ if ( !ctx->last ) {
+ RemoveProcessor( SCHEDULER_B_ID, 2 );
+ AddProcessor( SCHEDULER_C_ID, 2 );
+ SetScheduler( ctx->worker_id[ WORKER_C ], SCHEDULER_C_ID, PRIO_NORMAL );
+ }
+ }
+
+ if ( ( events & EVENT_BUSY ) != 0 ) {
+ while ( ctx->busy[ worker ] ) {
+ ++ctx->busy_counter[ worker ];
+ }
+ }
+
+ if ( ( events & EVENT_SYNC_RUNNER_LATE ) != 0 ) {
+ SendEvents( ctx->runner_id, EVENT_SYNC_RUNNER );
+ }
+ }
+ }
+
+ static void WorkerA( rtems_task_argument arg )
+ {
+ Worker( arg, WORKER_A );
+ }
+
+ static void WorkerB( rtems_task_argument arg )
+ {
+ Worker( arg, WORKER_B );
+ }
+
+ static void WorkerC( rtems_task_argument arg )
+ {
+ Worker( arg, WORKER_C );
+ }
+ #endif
test-target: testsuites/validation/tc-scheduler-remove-processor.c
-test-teardown: null
+test-teardown:
+ brief: null
+ code: |
+ #if defined(RTEMS_SMP)
+ DeleteTask( ctx->worker_id[ WORKER_A ] );
+ DeleteTask( ctx->worker_id[ WORKER_B ] );
+ DeleteTask( ctx->worker_id[ WORKER_C ] );
+ DeleteMutex( ctx->mutex_id );
+ DeleteMutex( ctx->sticky_id );
+ WrapThreadQueueDestroy( &ctx->wrap_tq_ctx );
+
+ if ( rtems_scheduler_get_processor_maximum() >= 4 ) {
+ AddProcessor( SCHEDULER_C_ID, 3 );
+ }
+
+ RestoreRunnerPriority();
+ SetSelfAffinityAll();
+ #endif
+ description: null
text: ${.:text-template}
transition-map:
- enabled-by: true
@@ -242,61 +804,193 @@ transition-map:
Status: InvId
Removed: Nop
pre-conditions:
- CPUState: N/A
Id:
- Invalid
CPUIndex: all
+ Owned: N/A
+ Last: N/A
+ Home: N/A
+ RequiredByAffinity: N/A
+ UsedBy: N/A
- enabled-by: true
post-conditions:
Status: InvNum
Removed: Nop
pre-conditions:
- CPUState: N/A
Id:
- Scheduler
CPUIndex:
- Invalid
+ Owned: N/A
+ Last: N/A
+ Home: N/A
+ RequiredByAffinity: N/A
+ UsedBy: N/A
- enabled-by: true
post-conditions:
- Status: InUse
+ Status: InvNum
Removed: Nop
pre-conditions:
- CPUState:
- - InUse
Id:
- Scheduler
CPUIndex:
- Valid
+ Owned:
+ - 'No'
+ Last: N/A
+ Home: N/A
+ RequiredByAffinity: N/A
+ UsedBy: N/A
- enabled-by: true
- post-conditions: OnlyOneCPU
+ post-conditions:
+ Status:
+ - if:
+ pre-conditions:
+ Last: 'Yes'
+ UsedBy: Helping
+ then: InUse
+ - else: Ok
+ Removed:
+ - if:
+ post-conditions:
+ Status: Ok
+ then: 'Yes'
+ - else: Nop
pre-conditions:
- CPUState:
- - Idle
- - NotOwned
Id:
- Scheduler
CPUIndex:
- Valid
-- enabled-by: RTEMS_SMP
+ Owned:
+ - 'Yes'
+ Last: all
+ Home:
+ - 'No'
+ RequiredByAffinity: N/A
+ UsedBy: all
+- enabled-by: true
post-conditions:
- Status: Ok
- Removed: 'Yes'
+ Status:
+ - if:
+ pre-conditions:
+ RequiredByAffinity: 'Yes'
+ then: InUse
+ - if:
+ pre-conditions:
+ Last: 'Yes'
+ UsedBy: Helping
+ then: InUse
+ - else: Ok
+ Removed:
+ - if:
+ post-conditions:
+ Status: Ok
+ then: 'Yes'
+ - else: Nop
pre-conditions:
- CPUState:
- - Idle
Id:
- Scheduler
CPUIndex:
- Valid
-- enabled-by: RTEMS_SMP
- post-conditions:
- Status: InvNum
- Removed: Nop
+ Owned:
+ - 'Yes'
+ Last: all
+ Home:
+ - 'Yes'
+ RequiredByAffinity: all
+ UsedBy: all
+- enabled-by: true
+ post-conditions: NoHomeNoTaskUser
+ pre-conditions:
+ Id:
+ - Scheduler
+ CPUIndex:
+ - Valid
+ Owned:
+ - 'Yes'
+ Last: all
+ Home:
+ - 'No'
+ RequiredByAffinity: N/A
+ UsedBy:
+ - Task
+ - TaskIdle
+- enabled-by: true
+ post-conditions: LastIsRequired
pre-conditions:
- CPUState:
- - NotOwned
Id:
- Scheduler
CPUIndex:
- Valid
+ Owned:
+ - 'Yes'
+ Last:
+ - 'Yes'
+ Home:
+ - 'Yes'
+ RequiredByAffinity:
+ - 'No'
+ UsedBy: all
+- enabled-by:
+ not: RTEMS_SMP
+ post-conditions: OnlyOneCPU
+ pre-conditions:
+ Id: all
+ CPUIndex: all
+ Owned:
+ - 'No'
+ Last: all
+ Home: all
+ RequiredByAffinity: all
+ UsedBy: all
+- enabled-by:
+ not: RTEMS_SMP
+ post-conditions: OnlyOneCPU
+ pre-conditions:
+ Id: all
+ CPUIndex: all
+ Owned: all
+ Last:
+ - 'No'
+ Home: all
+ RequiredByAffinity: all
+ UsedBy: all
+- enabled-by:
+ not: RTEMS_SMP
+ post-conditions: OnlyOneCPU
+ pre-conditions:
+ Id: all
+ CPUIndex: all
+ Owned: all
+ Last: all
+ Home:
+ - 'No'
+ RequiredByAffinity: all
+ UsedBy: all
+- enabled-by:
+ not: RTEMS_SMP
+ post-conditions: OnlyOneCPU
+ pre-conditions:
+ Id: all
+ CPUIndex: all
+ Owned: all
+ Last: all
+ Home:
+ - 'Yes'
+ RequiredByAffinity:
+ - 'No'
+ UsedBy: all
+- enabled-by:
+ not: RTEMS_SMP
+ post-conditions: OnlyOneCPU
+ pre-conditions:
+ Id: all
+ CPUIndex: all
+ Owned: all
+ Last: all
+ Home: all
+ RequiredByAffinity: all
+ UsedBy:
+ - TaskIdle
+ - Helping
type: requirement
diff --git a/spec/score/sched/smp/req/remove-last-processor-helping.yml b/spec/score/sched/smp/req/remove-last-processor-helping.yml
deleted file mode 100644
index db071e02..00000000
--- a/spec/score/sched/smp/req/remove-last-processor-helping.yml
+++ /dev/null
@@ -1,17 +0,0 @@
-SPDX-License-Identifier: CC-BY-SA-4.0
-copyrights:
-- Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de)
-enabled-by: RTEMS_SMP
-links:
-- role: requirement-refinement
- uid: group
-functional-type: function
-rationale: null
-references: []
-requirement-type: functional
-text: |
- While the processor allocated to a thread is owned by a
- ${/glossary/scheduler-helping:/term}, while the processor is the only
- processor of the scheduler, when the processor is removed, the thread shall
- be blocked with respect to the scheduler.
-type: requirement
diff --git a/spec/score/sched/smp/val/smp.yml b/spec/score/sched/smp/val/smp.yml
index b1563184..1e596184 100644
--- a/spec/score/sched/smp/val/smp.yml
+++ b/spec/score/sched/smp/val/smp.yml
@@ -5,50 +5,6 @@ enabled-by: RTEMS_SMP
links: []
test-actions:
- action-brief: |
- Use the mutex and the worker to construct the removal of the last processor
- of a scheduler while a thread is scheduled.
- action-code: |
- SMP_barrier_State barrier_state;
-
- _SMP_barrier_Control_initialize( &ctx->barrier );
- _SMP_barrier_State_initialize( &barrier_state );
-
- SetScheduler( ctx->worker_id[ WORKER_B ], SCHEDULER_B_ID, PRIO_NORMAL );
- checks:
- - brief: |
- Let worker B help worker A.
- code: |
- SendEvents( ctx->worker_id[ WORKER_A ], EVENT_OBTAIN );
- SendAndSync( ctx, WORKER_B, EVENT_OBTAIN );
- links: []
- - brief: |
- Restart the worker B to withdraw the help offer and wait on barriers.
- Move worker B to scheduler A. Remove the processor while worker A is
- scheduled.
- code: |
- SendEvents( ctx->worker_id[ WORKER_A ], EVENT_RESTART );
-
- /* A */
- _SMP_barrier_Wait( &ctx->barrier, &barrier_state, 2 );
-
- SetScheduler( ctx->worker_id[ WORKER_B ], SCHEDULER_A_ID, PRIO_HIGH );
- RemoveProcessor( SCHEDULER_B_ID, 1 );
-
- /* B */
- _SMP_barrier_Wait( &ctx->barrier, &barrier_state, 2 );
- links:
- - role: validation
- uid: ../req/remove-last-processor-helping
- - brief: |
- Clean up all used resources.
- code: |
- SetPriority( ctx->runner_id, PRIO_NORMAL );
- AddProcessor( SCHEDULER_B_ID, 1 );
- SendEvents( ctx->worker_id[ WORKER_A ], EVENT_RELEASE );
- SetScheduler( ctx->worker_id[ WORKER_B ], SCHEDULER_A_ID, PRIO_HIGH );
- links: []
- links: []
-- action-brief: |
Construct a system state in which a scheduler tries to schedule a node
those owner thread is already scheduled during a block operation.
action-code: |
@@ -343,21 +299,6 @@ test-context:
member: |
volatile bool busy[ WORKER_COUNT ];
- brief: |
- This member provides the context to wrap thread queue operations.
- description: null
- member: |
- WrapThreadQueueContext wrap_tq_ctx
-- brief: |
- This member contains the call within ISR request.
- description: null
- member: |
- CallWithinISRRequest request;
-- brief: |
- This member contains the barrier to synchronize the runner and the workers.
- description: null
- member: |
- SMP_barrier_Control barrier
-- brief: |
This member contains the per-CPU job.
description: null
member: |
@@ -380,7 +321,6 @@ test-includes:
- rtems.h
- rtems/test-scheduler.h
- rtems/score/percpu.h
-- rtems/score/smpbarrier.h
- rtems/score/thread.h
test-local-includes:
- tx-support.h
@@ -414,8 +354,6 @@ test-setup:
ctx->worker_id[ WORKER_C ] = CreateTask( "WRKC", PRIO_HIGH );
StartTask( ctx->worker_id[ WORKER_C ], WorkerC, ctx );
-
- WrapThreadQueueInitialize( &ctx->wrap_tq_ctx, RequestISR, ctx );
description: null
test-stop: null
test-support: |
@@ -425,35 +363,9 @@ test-support: |
EVENT_OBTAIN = RTEMS_EVENT_0,
EVENT_RELEASE = RTEMS_EVENT_1,
EVENT_SYNC_RUNNER = RTEMS_EVENT_2,
- EVENT_RESTART = RTEMS_EVENT_3,
- EVENT_BUSY = RTEMS_EVENT_4
+ EVENT_BUSY = RTEMS_EVENT_3
} Event;
- static void Barriers( void *arg )
- {
- Context *ctx;
- SMP_barrier_State barrier_state;
-
- ctx = arg;
- _SMP_barrier_State_initialize( &barrier_state );
-
- /* A */
- _SMP_barrier_Wait( &ctx->barrier, &barrier_state, 2 );
-
- /* B */
- _SMP_barrier_Wait( &ctx->barrier, &barrier_state, 2 );
- }
-
- static void RequestISR( void *arg )
- {
- Context *ctx;
-
- ctx = arg;
- ctx->request.handler = Barriers;
- ctx->request.arg = ctx;
- CallWithinISRSubmit( &ctx->request );
- }
-
static void SendAndSync( Context *ctx, WorkerIndex worker, Event event )
{
SendEvents( ctx->worker_id[ worker ], EVENT_SYNC_RUNNER | event );
@@ -683,27 +595,6 @@ test-support: |
ReleaseMutex( ctx->mutex_id );
}
- if ( ( events & EVENT_RESTART ) != 0 ) {
- rtems_status_code sc;
-
- T_eq_u32( rtems_scheduler_get_processor(), 0 );
- SetPriority( ctx->runner_id, PRIO_VERY_HIGH );
- T_eq_u32( rtems_scheduler_get_processor(), 1 );
-
- WrapThreadQueueExtract(
- &ctx->wrap_tq_ctx,
- GetThread( ctx->worker_id[ WORKER_B ] )
- );
-
- sc = rtems_task_restart(
- ctx->worker_id[ WORKER_B ],
- (rtems_task_argument) ctx
- );
- T_rsc_success( sc );
-
- T_eq_u32( rtems_scheduler_get_processor(), 0 );
- }
-
if ( ( events & EVENT_BUSY ) != 0 ) {
while ( ctx->busy[ worker ] ) {
/* Wait */
@@ -736,6 +627,5 @@ test-teardown:
DeleteMutex( ctx->mutex_id );
DeleteMutex( ctx->sticky_id );
RestoreRunnerPriority();
- WrapThreadQueueDestroy( &ctx->wrap_tq_ctx );
description: null
type: test-case