summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2021-09-28 14:38:27 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2021-09-29 08:01:06 +0200
commitfc13d6933a0d9a6ec15c73e0f81920d82e20ce95 (patch)
treeed45c78001352a3085140e06f1193adbdf0264cf
parentmodules: Update rtems (diff)
downloadrtems-central-fc13d6933a0d9a6ec15c73e0f81920d82e20ce95.tar.bz2
spec: Specify scheduler helping detail
-rw-r--r--spec/score/thread/req/suspended-helping.yml15
-rw-r--r--spec/score/thread/val/smp.yml232
2 files changed, 217 insertions, 30 deletions
diff --git a/spec/score/thread/req/suspended-helping.yml b/spec/score/thread/req/suspended-helping.yml
new file mode 100644
index 00000000..ab6de611
--- /dev/null
+++ b/spec/score/thread/req/suspended-helping.yml
@@ -0,0 +1,15 @@
+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: ../if/group
+functional-type: function
+rationale: |
+ This is an performance optimization.
+references: []
+requirement-type: functional
+text: |
+ While a thread is suspended, the thread shall not reconsider help requests.
+type: requirement
diff --git a/spec/score/thread/val/smp.yml b/spec/score/thread/val/smp.yml
index c88ef776..51bac130 100644
--- a/spec/score/thread/val/smp.yml
+++ b/spec/score/thread/val/smp.yml
@@ -8,24 +8,16 @@ test-actions:
Create three worker threads and a mutex. Use the mutex and the worker to
move to a helping scheduler.
action-code: |
- rtems_status_code sc;
- Per_CPU_Control *cpu_self;
- Thread_Control *executing;
+ Per_CPU_Control*cpu_self;
+ Thread_Control *executing;
executing = _Thread_Get_executing();
- SetSelfPriority( PRIO_NORMAL );
ctx->counter = 0;
- sc = rtems_scheduler_ident( TEST_SCHEDULER_A_NAME, &ctx->scheduler_a_id );
- T_rsc_success( sc );
-
- sc = rtems_scheduler_ident( TEST_SCHEDULER_B_NAME, &ctx->scheduler_b_id );
- T_rsc_success( sc );
-
ctx->mutex_id = CreateMutex();
ctx->worker_a_id = CreateTask( "WRKA", PRIO_NORMAL );
- SetScheduler( ctx->worker_a_id, ctx->scheduler_b_id, PRIO_NORMAL );
+ SetScheduler( ctx->worker_a_id, SCHEDULER_B_ID, PRIO_NORMAL );
StartTask( ctx->worker_a_id, WorkerTask, ctx );
ctx->worker_b_id = CreateTask( "WRKB", PRIO_HIGH );
@@ -64,7 +56,7 @@ test-actions:
shows that the pinning of the runner thread is maintained.
code: |
ctx->busy = false;
- SetScheduler( ctx->worker_b_id, ctx->scheduler_b_id, PRIO_HIGH );
+ SetScheduler( ctx->worker_b_id, SCHEDULER_B_ID, PRIO_HIGH );
SendEvents( ctx->worker_b_id, EVENT_LET_WORKER_C_COUNT );
T_eq_u32( rtems_scheduler_get_processor(), 1 );
@@ -110,33 +102,126 @@ test-actions:
- brief: |
Make sure the worker released the mutex.
code: |
- SetSelfScheduler( ctx->scheduler_b_id, PRIO_LOW );
- SetSelfScheduler( ctx->scheduler_a_id, PRIO_NORMAL );
+ SetSelfScheduler( SCHEDULER_B_ID, PRIO_LOW );
+ SetSelfScheduler( SCHEDULER_A_ID, PRIO_NORMAL );
+ links: []
+ - brief: |
+ Clean up all used resources.
+ code: |
+ DeleteTask( ctx->worker_a_id );
+ DeleteTask( ctx->worker_b_id );
+ DeleteTask( ctx->worker_c_id );
+ DeleteMutex( ctx->mutex_id );
+ links: []
+ links: []
+- action-brief: |
+ Create three worker threads and a mutex. Use the mutex and the worker to
+ check that a suspended thread does not reconsider help requests.
+ action-code: |
+ T_scheduler_log_10 scheduler_log;
+ size_t index;
+ const T_scheduler_event *event;
+
+ _SMP_barrier_Control_initialize( &ctx->barrier );
+ _SMP_barrier_State_initialize( &ctx->barrier_state );
+
+ ctx->counter = 0;
+ ctx->mutex_id = CreateMutex();
+
+ ctx->worker_a_id = CreateTask( "WRKA", PRIO_NORMAL );
+ SetScheduler( ctx->worker_a_id, SCHEDULER_B_ID, PRIO_NORMAL );
+ StartTask( ctx->worker_a_id, WorkerTask, ctx );
+
+ ctx->worker_b_id = CreateTask( "WRKB", PRIO_HIGH );
+ StartTask( ctx->worker_b_id, WorkerTask, ctx );
+
+ ctx->worker_c_id = CreateTask( "WRKC", PRIO_NORMAL );
+ SetScheduler( ctx->worker_c_id, SCHEDULER_B_ID, PRIO_HIGH );
+ StartTask( ctx->worker_c_id, WorkerTask, ctx );
+ checks:
+ - brief: |
+ Let worker B help worker A through the mutex. Preempt worker A. Delay
+ the thread switch to worker A.
+ code: |
+ ctx->busy = true;
+ SendEvents(
+ ctx->worker_a_id,
+ EVENT_OBTAIN | EVENT_COUNT_EARLY | EVENT_BUSY | EVENT_COUNT
+ );
+ WaitForCounter( ctx, 1 );
+
+ SendEvents( ctx->worker_b_id, EVENT_OBTAIN );
+ SetPriority( ctx->worker_b_id, PRIO_LOW );
+ SendEvents( ctx->worker_c_id, EVENT_SET_TASK_SWITCH_EXTENSION );
+
+ /* B0 */
+ _SMP_barrier_Wait( &ctx->barrier, &ctx->barrier_state, 2 );
+ links: []
+ - brief: |
+ Suspend worker A and let it wait on its thread state lock. Check that
+ worker A did not reconsider help requests.
+ code: |
+ T_scheduler_record_10( &scheduler_log );
+ T_scheduler_set_event_handler( SchedulerBlock, ctx );
+ SuspendTask( ctx->worker_a_id );
+ WaitForExecutionStop( ctx->worker_a_id );
+ T_scheduler_record( NULL );
+ T_eq_sz( scheduler_log.header.recorded, 2 );
+ index = 0;
+ event = T_scheduler_next_any( &scheduler_log.header, &index );
+ T_eq_int( event->operation, T_SCHEDULER_BLOCK );
+ event = T_scheduler_next_any( &scheduler_log.header, &index );
+ T_eq_int( event->operation, T_SCHEDULER_WITHDRAW_NODE );
+ event = T_scheduler_next_any( &scheduler_log.header, &index );
+ T_eq_ptr( event, &T_scheduler_event_null );
+ SetTaskSwitchExtension( NULL );
+ links:
+ - role: validation
+ uid: ../req/suspended-helping
+ - brief: |
+ Resume worker A. Check that worker A did reconsider help requests after
+ the thread dispatch.
+ code: |
+ T_scheduler_record_10( &scheduler_log );
+ ResumeTask( ctx->worker_a_id );
+ ctx->busy = false;
+ WaitForCounter( ctx, 2 );
+ WaitForExecutionStop( ctx->worker_a_id );
+ T_scheduler_record( NULL );
+ T_eq_sz( scheduler_log.header.recorded, 5 );
+ index = 0;
+ event = T_scheduler_next_any( &scheduler_log.header, &index );
+ T_eq_int( event->operation, T_SCHEDULER_UNBLOCK );
+ event = T_scheduler_next_any( &scheduler_log.header, &index );
+ T_eq_int( event->operation, T_SCHEDULER_RECONSIDER_HELP_REQUEST );
+ event = T_scheduler_next_any( &scheduler_log.header, &index );
+ T_eq_int( event->operation, T_SCHEDULER_RECONSIDER_HELP_REQUEST );
+ event = T_scheduler_next_any( &scheduler_log.header, &index );
+ T_eq_int( event->operation, T_SCHEDULER_BLOCK );
+ event = T_scheduler_next_any( &scheduler_log.header, &index );
+ T_eq_int( event->operation, T_SCHEDULER_WITHDRAW_NODE );
+ event = T_scheduler_next_any( &scheduler_log.header, &index );
+ T_eq_ptr( event, &T_scheduler_event_null );
links: []
- brief: |
Clean up all used resources.
code: |
+ SendEvents( ctx->worker_a_id, EVENT_RELEASE | EVENT_COUNT );
+ WaitForCounter( ctx, 3 );
+
+ SetPriority( ctx->worker_b_id, PRIO_HIGH );
+ SendEvents( ctx->worker_b_id, EVENT_RELEASE );
+
DeleteTask( ctx->worker_a_id );
DeleteTask( ctx->worker_b_id );
DeleteTask( ctx->worker_c_id );
DeleteMutex( ctx->mutex_id );
- RestoreRunnerPriority();
links: []
links: []
test-brief: |
Tests SMP-specific thread behaviour.
test-context:
- brief: |
- This member contains the scheduler A identifier.
- description: null
- member: |
- rtems_id scheduler_a_id
-- brief: |
- This member contains the scheduler B identifier.
- description: null
- member: |
- rtems_id scheduler_b_id
-- brief: |
This member contains the worker A identifier.
description: null
member: |
@@ -166,16 +251,32 @@ test-context:
description: null
member: |
volatile uint32_t counter
+- 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 barrier state for the runner processor.
+ description: null
+ member: |
+ SMP_barrier_State barrier_state
test-context-support: null
test-description: null
test-header: null
test-includes:
- rtems.h
+- rtems/test-scheduler.h
+- rtems/score/smpbarrier.h
- rtems/score/threadimpl.h
test-local-includes:
- ts-config.h
- tx-support.h
-test-setup: null
+test-setup:
+ brief: null
+ code: |
+ SetSelfPriority( PRIO_NORMAL );
+ description: null
test-stop: null
test-support: |
typedef ${.:/test-context-type} Context;
@@ -183,11 +284,37 @@ test-support: |
typedef enum {
EVENT_OBTAIN = RTEMS_EVENT_0,
EVENT_RELEASE = RTEMS_EVENT_1,
- EVENT_BUSY = RTEMS_EVENT_2,
- EVENT_COUNT = RTEMS_EVENT_3,
- EVENT_LET_WORKER_C_COUNT = RTEMS_EVENT_4
+ EVENT_COUNT_EARLY = RTEMS_EVENT_2,
+ EVENT_BUSY = RTEMS_EVENT_3,
+ EVENT_COUNT = RTEMS_EVENT_4,
+ EVENT_LET_WORKER_C_COUNT = RTEMS_EVENT_5,
+ EVENT_SET_TASK_SWITCH_EXTENSION = RTEMS_EVENT_6
} Event;
+ static void TaskSwitchExtension( rtems_tcb *executing, rtems_tcb *heir )
+ {
+ Context *ctx;
+ Thread_Control *thread;
+
+ (void) executing;
+ (void) heir;
+
+ ctx = T_fixture_context();
+ thread = GetThread( ctx->worker_a_id );
+
+ if ( thread == heir ) {
+ SMP_barrier_State state;
+
+ _SMP_barrier_State_initialize( &state );
+
+ /* B0 */
+ _SMP_barrier_Wait( &ctx->barrier, &state, 2 );
+
+ /* B1 */
+ _SMP_barrier_Wait( &ctx->barrier, &state, 2 );
+ }
+ }
+
static void WorkerTask( rtems_task_argument arg )
{
Context *ctx;
@@ -207,6 +334,10 @@ test-support: |
ReleaseMutex( ctx->mutex_id );
}
+ if ( ( events & EVENT_COUNT_EARLY ) != 0 ) {
+ ++ctx->counter;
+ }
+
if ( ( events & EVENT_BUSY ) != 0 ) {
while ( ctx->busy ) {
/* Do nothing */
@@ -227,6 +358,36 @@ test-support: |
/* Wait */
}
}
+
+ if ( ( events & EVENT_SET_TASK_SWITCH_EXTENSION ) != 0 ) {
+ SetTaskSwitchExtension( TaskSwitchExtension );
+ }
+ }
+ }
+
+ static void SchedulerBlock(
+ void *arg,
+ const T_scheduler_event *event,
+ T_scheduler_when when
+ )
+ {
+ Context *ctx;
+
+ ctx = arg;
+
+ if (
+ when == T_SCHEDULER_BEFORE &&
+ event->operation == T_SCHEDULER_BLOCK
+ ) {
+ Thread_Control *thread;
+
+ T_scheduler_set_event_handler( NULL, NULL );
+
+ /* B1 */
+ _SMP_barrier_Wait( &ctx->barrier, &ctx->barrier_state, 2 );
+
+ thread = GetThread( ctx->worker_a_id );
+ TicketLockWaitForOthers( &thread->Join_queue.Queue.Lock, 1 );
}
}
@@ -245,6 +406,17 @@ test-support: |
thread = arg;
ResumeTask( thread->Object.id );
}
+
+ static void WaitForCounter( const Context *ctx, uint32_t expected )
+ {
+ while ( ctx->counter != expected ) {
+ /* Wait */
+ }
+ }
test-target: testsuites/validation/tc-score-smp-thread.c
-test-teardown: null
+test-teardown:
+ brief: null
+ code: |
+ RestoreRunnerPriority();
+ description: null
type: test-case