[rtems-central commit] spec: Specify scheduler helping detail

Sebastian Huber sebh at rtems.org
Wed Sep 29 12:18:08 UTC 2021


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

Author:    Sebastian Huber <sebastian.huber at embedded-brains.de>
Date:      Tue Sep 28 14:38:27 2021 +0200

spec: Specify scheduler helping detail

---

 spec/score/thread/req/suspended-helping.yml |  15 ++
 spec/score/thread/val/smp.yml               | 232 ++++++++++++++++++++++++----
 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 0000000..ab6de61
--- /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 c88ef77..51bac13 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



More information about the vc mailing list