[rtems-central commit] spec: Improve SMP-specific timecounter validation

Sebastian Huber sebh at rtems.org
Thu Oct 28 18:14:04 UTC 2021


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

Author:    Sebastian Huber <sebastian.huber at embedded-brains.de>
Date:      Thu Oct 28 16:09:26 2021 +0200

spec: Improve SMP-specific timecounter validation

---

 spec/score/timecounter/val/get-smp.yml | 670 +++++++++++++++++++++++++++++----
 1 file changed, 603 insertions(+), 67 deletions(-)

diff --git a/spec/score/timecounter/val/get-smp.yml b/spec/score/timecounter/val/get-smp.yml
index d3257d7..dd09b35 100644
--- a/spec/score/timecounter/val/get-smp.yml
+++ b/spec/score/timecounter/val/get-smp.yml
@@ -9,54 +9,427 @@ test-actions:
   action-code: |
     Timecounter     *tc;
     rtems_id         worker_id;
-    Per_CPU_Control *cpu_self;
+    struct bintime   bt;
+    sbintime_t       sbt;
+    struct timespec  ts;
+    struct timeval   tv;
+    unsigned int     i;
 
     tc = &test_timecounter;
+    tc->base.tc_get_timecount = GetTimecount;
+    tc->base.tc_counter_mask = 0xffffffff;
+    tc->base.tc_frequency = 0x10000000;
+    tc->base.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
+    rtems_timecounter_install( &tc->base );
+
+    SetCounter( tc, tc->base.tc_frequency );
+    _Timecounter_Set_NTP_update_second( NtpUpdateSecond );
+    CallTimecounterTick();
+    _Timecounter_Set_NTP_update_second( NULL );
+
+    T_assert_not_null( tc->generation_0 );
+    T_assert_not_null( tc->generation_1 );
+
     _SMP_barrier_Control_initialize( &tc->barrier );
     _SMP_barrier_State_initialize( &tc->barrier_state[ 0 ] );
     _SMP_barrier_State_initialize( &tc->barrier_state[ 1 ] );
 
     worker_id = CreateTask( "WORK", PRIO_NORMAL );
     SetScheduler( worker_id, SCHEDULER_B_ID, PRIO_NORMAL );
-    StartTask( worker_id, Worker, tc );
+    StartTask( worker_id, SynchronousWorker, tc );
 
-    tc->base.tc_get_timecount = GetTimecount;
-    tc->base.tc_counter_mask = 0xffffffff;
-    tc->base.tc_frequency = 0x10000000;
-    tc->base.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
-    rtems_timecounter_install( &tc->base );
-
-    /* A */
-    _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 0 ], 2 );
+    tc->base.tc_get_timecount = GetTimecountBarrier;
   checks:
   - brief: |
-      Install a timecounter with a high quality level and normal frequency.
-      Check that it was installed.
+      Call the ${/rtems/clock/if/get-realtime:/name} directive and let it
+      observe a generation number of zero as well as a generation number
+      change.
     code: |
-      /* B0 */
-      _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 0 ], 2 );
+      PrepareSynchronousWork( tc );
+      rtems_clock_get_realtime( &ts );
+      T_eq_i64( ts.tv_sec, 567993616 );
+      T_eq_long( ts.tv_nsec, 7 );
+      CleanupSynchronousWork( tc );
+    links:
+    - role: validation
+      uid: ../req/get-non-blocking
+    - role: validation
+      uid: /rtems/clock/req/get-realtime
+  - brief: |
+      Call the ${/rtems/clock/if/get-realtime-bintime:/name} directive and let
+      it observe a generation number of zero as well as a generation number
+      change.
+    code: |
+      PrepareSynchronousWork( tc );
+      rtems_clock_get_realtime_bintime( &bt );
+      T_eq_i64( bt.sec, 567993616 );
+      T_eq_u64( bt.frac, 137438953472 );
+      CleanupSynchronousWork( tc );
+    links:
+    - role: validation
+      uid: ../req/get-non-blocking
+    - role: validation
+      uid: /rtems/clock/req/get-realtime
+  - brief: |
+      Call the ${/rtems/clock/if/get-realtime-timeval:/name} directive and let
+      it observe a generation number of zero as well as a generation number
+      change.
+    code: |
+      PrepareSynchronousWork( tc );
+      rtems_clock_get_realtime_timeval( &tv );
+      T_eq_i64( tv.tv_sec, 567993616 );
+      T_eq_long( tv.tv_usec, 0 );
+      CleanupSynchronousWork( tc );
+    links:
+    - role: validation
+      uid: ../req/get-non-blocking
+    - role: validation
+      uid: /rtems/clock/req/get-realtime
+  - brief: |
+      Call the ${/rtems/clock/if/get-monotonic:/name} directive and let it
+      observe a generation number of zero as well as a generation number
+      change.
+    code: |
+      PrepareSynchronousWork( tc );
+      rtems_clock_get_monotonic( &ts );
+      T_eq_i64( ts.tv_sec, 17 );
+      T_eq_long( ts.tv_nsec, 7 );
+      CleanupSynchronousWork( tc );
+    links:
+    - role: validation
+      uid: ../req/get-non-blocking
+    - role: validation
+      uid: /rtems/clock/req/get-monotonic
+  - brief: |
+      Call the ${/rtems/clock/if/get-monotonic-bintime:/name} directive and let
+      it observe a generation number of zero as well as a generation number
+      change.
+    code: |
+      PrepareSynchronousWork( tc );
+      rtems_clock_get_monotonic_bintime( &bt );
+      T_eq_i64( bt.sec, 17 );
+      T_eq_u64( bt.frac, 137438953472 );
+      CleanupSynchronousWork( tc );
+    links:
+    - role: validation
+      uid: ../req/get-non-blocking
+    - role: validation
+      uid: /rtems/clock/req/get-monotonic
+  - brief: |
+      Call the ${/rtems/clock/if/get-monotonic-sbintime:/name} directive and let
+      it observe a generation number of zero as well as a generation number
+      change.
+    code: |
+      PrepareSynchronousWork( tc );
+      sbt = rtems_clock_get_monotonic_sbintime();
+      T_eq_i64( sbt, 73014444064 );
+      CleanupSynchronousWork( tc );
+    links:
+    - role: validation
+      uid: ../req/get-non-blocking
+    - role: validation
+      uid: /rtems/clock/req/get-monotonic
+  - brief: |
+      Call the ${/rtems/clock/if/get-monotonic-timeval:/name} directive and let
+      it observe a generation number of zero as well as a generation number
+      change.
+    code: |
+      PrepareSynchronousWork( tc );
+      rtems_clock_get_monotonic_timeval( &tv );
+      T_eq_i64( tv.tv_sec, 17 );
+      T_eq_long( tv.tv_usec, 0 );
+      CleanupSynchronousWork( tc );
+    links:
+    - role: validation
+      uid: ../req/get-non-blocking
+    - role: validation
+      uid: /rtems/clock/req/get-monotonic
+  - brief: |
+      Delete the synchronous worker task.  Reinitialize the barrier and barrier
+      states.  Start the zero worker task.
+    code: |
+      tc->base.tc_get_timecount = GetTimecount;
+      DeleteTask( worker_id );
 
-      /* B1 */
-      _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 0 ], 2 );
+      _SMP_barrier_Control_initialize( &tc->barrier );
+      _SMP_barrier_State_initialize( &tc->barrier_state[ 0 ] );
+      _SMP_barrier_State_initialize( &tc->barrier_state[ 1 ] );
 
-      cpu_self = _Thread_Dispatch_disable();
-      tc->delay = false;
-      rtems_timecounter_tick();
-      tc->delay = true;
-      rtems_timecounter_tick();
-      _Thread_Dispatch_enable( cpu_self );
+      worker_id = CreateTask( "WORK", PRIO_NORMAL );
+      SetScheduler( worker_id, SCHEDULER_B_ID, PRIO_NORMAL );
+      StartTask( worker_id, ZeroWorker, tc );
+    links: []
+  - brief: |
+      Call the ${/rtems/clock/if/get-realtime-coarse:/name} directive and try
+      to let it observe a generation number of zero.
+    code: |
+      PrepareZeroWork( tc );
+      rtems_clock_get_realtime_coarse( &ts );
+      CleanupZeroWork( tc );
+    links:
+    - role: validation
+      uid: ../req/get-non-blocking
+    - role: validation
+      uid: /rtems/clock/req/get-realtime-coarse
+  - brief: |
+      Call the ${/rtems/clock/if/get-realtime-coarse-bintime:/name} directive
+      and try to let it observe a generation number of zero.
+    code: |
+      PrepareZeroWork( tc );
+      rtems_clock_get_realtime_coarse_bintime( &bt );
+      CleanupZeroWork( tc );
+    links:
+    - role: validation
+      uid: ../req/get-non-blocking
+    - role: validation
+      uid: /rtems/clock/req/get-realtime-coarse
+  - brief: |
+      Call the ${/rtems/clock/if/get-realtime-coarse-timeval:/name} directive
+      and try to let it observe a generation number of zero.
+    code: |
+      PrepareZeroWork( tc );
+      rtems_clock_get_realtime_coarse_timeval( &tv );
+      CleanupZeroWork( tc );
+    links:
+    - role: validation
+      uid: ../req/get-non-blocking
+    - role: validation
+      uid: /rtems/clock/req/get-realtime-coarse
+  - brief: |
+      Call the ${/rtems/clock/if/get-monotonic-coarse:/name} directive and try
+      to let it observe a generation number of zero.
+    code: |
+      PrepareZeroWork( tc );
+      rtems_clock_get_monotonic_coarse( &ts );
+      CleanupZeroWork( tc );
+    links:
+    - role: validation
+      uid: ../req/get-non-blocking
+    - role: validation
+      uid: /rtems/clock/req/get-monotonic-coarse
+  - brief: |
+      Call the ${/rtems/clock/if/get-monotonic-coarse-bintime:/name} directive
+      and try to let it observe a generation number of zero.
+    code: |
+      PrepareZeroWork( tc );
+      rtems_clock_get_monotonic_coarse_bintime( &bt );
+      CleanupZeroWork( tc );
+    links:
+    - role: validation
+      uid: ../req/get-non-blocking
+    - role: validation
+      uid: /rtems/clock/req/get-monotonic-coarse
+  - brief: |
+      Call the ${/rtems/clock/if/get-monotonic-coarse-timeval:/name} directive
+      and try to let it observe a generation number of zero.
+    code: |
+      PrepareZeroWork( tc );
+      rtems_clock_get_monotonic_coarse_timeval( &tv );
+      CleanupZeroWork( tc );
+    links:
+    - role: validation
+      uid: ../req/get-non-blocking
+    - role: validation
+      uid: /rtems/clock/req/get-monotonic-coarse
+  - brief: |
+      Call the ${/rtems/clock/if/get-boot-time:/name} directive and try
+      to let it observe a generation number of zero.
+    code: |
+      PrepareZeroWork( tc );
+      rtems_clock_get_boot_time( &ts );
+      CleanupZeroWork( tc );
+    links:
+    - role: validation
+      uid: ../req/get-non-blocking
+    - role: validation
+      uid: /rtems/clock/req/get-boot-time
+  - brief: |
+      Call the ${/rtems/clock/if/get-boot-time-bintime:/name} directive
+      and try to let it observe a generation number of zero.
+    code: |
+      PrepareZeroWork( tc );
+      rtems_clock_get_boot_time_bintime( &bt );
+      CleanupZeroWork( tc );
+    links:
+    - role: validation
+      uid: ../req/get-non-blocking
+    - role: validation
+      uid: /rtems/clock/req/get-boot-time
+  - brief: |
+      Call the ${/rtems/clock/if/get-boot-time-timeval:/name} directive
+      and try to let it observe a generation number of zero.
+    code: |
+      PrepareZeroWork( tc );
+      rtems_clock_get_boot_time_timeval( &tv );
+      CleanupZeroWork( tc );
+    links:
+    - role: validation
+      uid: ../req/get-non-blocking
+    - role: validation
+      uid: /rtems/clock/req/get-boot-time
+  - brief: |
+      Delete the zero worker task.  Reinitialize the barrier and barrier
+      states.  Start the change worker task.
+    code: |
+      DeleteTask( worker_id );
+
+      _SMP_barrier_Control_initialize( &tc->barrier );
+      _SMP_barrier_State_initialize( &tc->barrier_state[ 0 ] );
+      _SMP_barrier_State_initialize( &tc->barrier_state[ 1 ] );
+
+      worker_id = CreateTask( "WORK", PRIO_NORMAL );
+      SetScheduler( worker_id, SCHEDULER_B_ID, PRIO_NORMAL );
+      StartTask( worker_id, ChangeWorker, tc );
+    links: []
+  - brief: |
+      Call the ${/rtems/clock/if/get-realtime-coarse:/name} directive and try
+      to let it observe a changing generation number.
+    code: |
+      PrepareChangeWork( tc );
 
-      /* B4 */
-      _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 0 ], 2 );
+      for ( i = 0; i < 100; ++i ) {
+        rtems_clock_get_realtime_coarse( &ts );
+      }
 
-      /* B5 */
-      _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 0 ], 2 );
+      CleanupChangeWork( tc );
+    links:
+    - role: validation
+      uid: ../req/get-non-blocking
+    - role: validation
+      uid: /rtems/clock/req/get-realtime-coarse
+  - brief: |
+      Call the ${/rtems/clock/if/get-realtime-coarse-bintime:/name} directive
+      and try to let it observe a changing generation number.
+    code: |
+      PrepareChangeWork( tc );
 
-      tc->base.tc_get_timecount = GetTimecountDummy;
-      DeleteTask( worker_id );
+      for ( i = 0; i < 100; ++i ) {
+        rtems_clock_get_realtime_coarse_bintime( &bt );
+      }
+
+      CleanupChangeWork( tc );
+    links:
+    - role: validation
+      uid: ../req/get-non-blocking
+    - role: validation
+      uid: /rtems/clock/req/get-realtime-coarse
+  - brief: |
+      Call the ${/rtems/clock/if/get-realtime-coarse-timeval:/name} directive
+      and try to let it observe a changing generation number.
+    code: |
+      PrepareChangeWork( tc );
+
+      for ( i = 0; i < 100; ++i ) {
+        rtems_clock_get_realtime_coarse_timeval( &tv );
+      }
+
+      CleanupChangeWork( tc );
+    links:
+    - role: validation
+      uid: ../req/get-non-blocking
+    - role: validation
+      uid: /rtems/clock/req/get-realtime-coarse
+  - brief: |
+      Call the ${/rtems/clock/if/get-monotonic-coarse:/name} directive and try
+      to let it observe a changing generation number.
+    code: |
+      PrepareChangeWork( tc );
+
+      for ( i = 0; i < 100; ++i ) {
+        rtems_clock_get_monotonic_coarse( &ts );
+      }
+
+      CleanupChangeWork( tc );
+    links:
+    - role: validation
+      uid: ../req/get-non-blocking
+    - role: validation
+      uid: /rtems/clock/req/get-monotonic-coarse
+  - brief: |
+      Call the ${/rtems/clock/if/get-monotonic-coarse-bintime:/name} directive
+      and try to let it observe a changing generation number.
+    code: |
+      PrepareChangeWork( tc );
+
+      for ( i = 0; i < 100; ++i ) {
+        rtems_clock_get_monotonic_coarse_bintime( &bt );
+      }
+
+      CleanupChangeWork( tc );
+    links:
+    - role: validation
+      uid: ../req/get-non-blocking
+    - role: validation
+      uid: /rtems/clock/req/get-monotonic-coarse
+  - brief: |
+      Call the ${/rtems/clock/if/get-monotonic-coarse-timeval:/name} directive
+      and try to let it observe a changing generation number.
+    code: |
+      PrepareChangeWork( tc );
+
+      for ( i = 0; i < 100; ++i ) {
+        rtems_clock_get_monotonic_coarse_timeval( &tv );
+      }
+
+      CleanupChangeWork( tc );
     links:
     - role: validation
-      uid: ../req/install-quality
+      uid: ../req/get-non-blocking
+    - role: validation
+      uid: /rtems/clock/req/get-monotonic-coarse
+  - brief: |
+      Call the ${/rtems/clock/if/get-boot-time:/name} directive and try
+      to let it observe a changing generation number.
+    code: |
+      PrepareChangeWork( tc );
+
+      for ( i = 0; i < 100; ++i ) {
+        rtems_clock_get_boot_time( &ts );
+      }
+
+      CleanupChangeWork( tc );
+    links:
+    - role: validation
+      uid: ../req/get-non-blocking
+    - role: validation
+      uid: /rtems/clock/req/get-boot-time
+  - brief: |
+      Call the ${/rtems/clock/if/get-boot-time-bintime:/name} directive
+      and try to let it observe a changing generation number.
+    code: |
+      PrepareChangeWork( tc );
+
+      for ( i = 0; i < 100; ++i ) {
+        rtems_clock_get_boot_time_bintime( &bt );
+      }
+
+      CleanupChangeWork( tc );
+    links:
+    - role: validation
+      uid: ../req/get-non-blocking
+    - role: validation
+      uid: /rtems/clock/req/get-boot-time
+  - brief: |
+      Call the ${/rtems/clock/if/get-boot-time-timeval:/name} directive
+      and try to let it observe a changing generation number.
+    code: |
+      PrepareChangeWork( tc );
+
+      for ( i = 0; i < 100; ++i ) {
+        rtems_clock_get_boot_time_timeval( &tv );
+      }
+
+      CleanupChangeWork( tc );
+    links:
+    - role: validation
+      uid: ../req/get-non-blocking
+    - role: validation
+      uid: /rtems/clock/req/get-boot-time
+  - brief: |
+      Delete the change worker task.
+    code: |
+      DeleteTask( worker_id );
+    links: []
   links: []
 test-brief: |
   Tests directives to get a time value.
@@ -66,6 +439,7 @@ test-description: null
 test-header: null
 test-includes:
 - rtems.h
+- rtems/counter.h
 - rtems/timecounter.h
 - rtems/score/threaddispatch.h
 - rtems/score/smpbarrier.h
@@ -76,8 +450,9 @@ test-stop: null
 test-support: |
   typedef struct {
     struct timecounter  base;
-    bool                delay;
-    uint32_t            counter;
+    Atomic_Ulong        counter;
+    Atomic_Uint        *generation_0;
+    Atomic_Uint        *generation_1;
     SMP_barrier_Control barrier;
     SMP_barrier_State   barrier_state[ 2 ];
   } Timecounter;
@@ -90,71 +465,232 @@ test-support: |
 
     tc = (Timecounter *) base;
 
-    if ( rtems_scheduler_get_processor() == 0 ) {
-      if ( !tc->delay ) {
-        return 0;
-      }
+    return (uint32_t) _Atomic_Fetch_add_ulong(
+      &tc->counter,
+      1,
+      ATOMIC_ORDER_RELAXED
+    );
+  }
 
-      /* B2 */
-      _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 0 ], 2 );
+  static uint32_t GetTimecountBarrier( struct timecounter *base )
+  {
+    Timecounter *tc;
 
-      /* B3 */
-      _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 0 ], 2 );
+    tc = (Timecounter *) base;
 
-      return 0;
-    }
+    /* C0, C1, C2 */
+    _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 0 ], 2 );
+
+    /* D0, D1, D2 */
+    _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 0 ], 2 );
+
+    return GetTimecount( &tc->base );
+  }
+
+  static uint32_t GetCounter( const Timecounter *tc )
+  {
+    return (uint32_t) _Atomic_Load_ulong(
+      &tc->counter,
+      ATOMIC_ORDER_RELAXED
+    );
+  }
+
+  static void SetCounter( Timecounter *tc, uint32_t counter )
+  {
+    _Atomic_Store_ulong(
+      &tc->counter,
+      counter,
+      ATOMIC_ORDER_RELAXED
+    );
+  }
+
+  static void CallTimecounterTick( void )
+  {
+    Per_CPU_Control *cpu_self;
 
-    if ( tc->counter == 0 ) {
-      /* Do nothing */
-    } else if ( tc->counter == 1 ) {
-      tc->counter = 2;
+    cpu_self = _Thread_Dispatch_disable();
+    rtems_timecounter_tick();
+    _Thread_Dispatch_enable( cpu_self );
+  }
+
+  static void SetGeneration( Timecounter *tc, unsigned int generation )
+  {
+    _Atomic_Store_uint( tc->generation_0, generation, ATOMIC_ORDER_RELAXED );
+    _Atomic_Store_uint( tc->generation_1, generation, ATOMIC_ORDER_RELAXED );
+  }
+
+  static void PrepareSynchronousWork( Timecounter *tc )
+  {
+    /* A */
+    _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 0 ], 2 );
+
+    SetCounter( tc, 0 );
+
+    /* B */
+    _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 0 ], 2 );
+  }
 
-      /* B1 */
+  static void CleanupSynchronousWork( Timecounter *tc )
+  {
+    /* E */
+    _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 0 ], 2 );
+
+    T_eq_u32( GetCounter( tc ), 3 );
+  }
+
+  static void SynchronousWorker( rtems_task_argument arg )
+  {
+    Timecounter *tc;
+
+    tc = (Timecounter *) arg;
+
+    while ( true ) {
+      /* A */
+      _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 );
+
+      SetGeneration( tc, 0 );
+
+      /* B */
+      _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 );
+
+      /* C0 */
+      _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 );
+
+      SetGeneration( tc, 1 );
+
+      /* D0 */
       _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 );
 
-      /* B2 */
+      /* C1 */
       _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 );
-    } else if ( tc->counter == 2 ) {
-      tc->counter = 3;
 
-      /* B3 */
+      SetGeneration( tc, 2 );
+
+      /* D1 */
       _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 );
 
-      /* B4 */
+      /* C2 */
+      _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 );
+
+      /* D2 */
+      _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 );
+
+      /* E */
       _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 );
     }
+  }
 
-    return 0;
+  static void PrepareZeroWork( Timecounter *tc )
+  {
+    /* F */
+    _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 0 ], 2 );
+
+    SetCounter( tc, 0 );
+
+    /* G */
+    _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 0 ], 2 );
   }
 
-  static uint32_t GetTimecountDummy( struct timecounter *base )
+  static void CleanupZeroWork( Timecounter *tc )
   {
-    (void) base;
+    /* H */
+    _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 0 ], 2 );
 
-    return 0;
+    T_eq_u32( GetCounter( tc ), 0 );
   }
 
-  static void Worker( rtems_task_argument arg )
+  static void ZeroWorker( rtems_task_argument arg )
   {
-    Timecounter   *tc;
-    struct bintime bt;
+    Timecounter *tc;
 
     tc = (Timecounter *) arg;
 
-    /* A */
-    _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 );
+    while ( true ) {
+      /* F */
+      _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 );
+
+      SetGeneration( tc, 0 );
 
-    tc->counter = 1;
+      /* G */
+      _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 );
+
+      rtems_counter_delay_nanoseconds( 10000000 );
+      SetGeneration( tc, 1 );
+
+      /* H */
+      _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 );
+    }
+  }
+
+  static void PrepareChangeWork( Timecounter *tc )
+  {
+    /* F */
+    _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 0 ], 2 );
+
+    SetCounter( tc, 0 );
+
+    /* G */
+    _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 0 ], 2 );
+  }
+
+  static void CleanupChangeWork( Timecounter *tc )
+  {
+    /* H */
+    _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 0 ], 2 );
+
+    T_eq_u32( GetCounter( tc ), 0 );
+  }
 
-    /* B0 */
-    _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 );
+  static void ChangeWorker( rtems_task_argument arg )
+  {
+    Timecounter *tc;
 
-    rtems_clock_get_realtime_bintime( &bt );
+    tc = (Timecounter *) arg;
 
-    /* B5 */
-    _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 );
+    while ( true ) {
+      unsigned int i;
 
-    ReceiveAnyEvents();
+      /* F */
+      _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 );
+
+      /* G */
+      _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 );
+
+      for ( i = 1; i < 1000; ++i ) {
+        SetGeneration( tc, i );
+      }
+
+      /* H */
+      _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 );
+    }
+  }
+
+  /* This definition must be identical to the one in kern_tc.c */
+  struct timehands {
+    struct timecounter *th_counter;
+    int64_t             th_adjustment;
+    uint64_t            th_scale;
+    uint32_t            th_large_delta;
+    uint32_t            th_offset_count;
+    struct bintime      th_offset;
+    struct bintime      th_bintime;
+    struct timeval      th_microtime;
+    struct timespec     th_nanotime;
+    struct bintime      th_boottime;
+    Atomic_Uint         th_generation;
+    struct timehands   *th_next;
+  };
+
+  static void NtpUpdateSecond( int64_t *adjustment, time_t *newsec )
+  {
+    Timecounter      *tc;
+    struct timehands *th;
+
+    tc = &test_timecounter;
+    th = RTEMS_CONTAINER_OF( adjustment, struct timehands, th_adjustment );
+    T_assert_eq_ptr( th, th->th_next->th_next );
+    tc->generation_0 = &th->th_generation;
+    tc->generation_1 = &th->th_next->th_generation;
   }
 test-target: testsuites/validation/tc-timecounter-get-smp.c
 test-teardown: null



More information about the vc mailing list