diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2021-10-28 16:09:26 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2021-10-28 19:51:56 +0200 |
commit | 45237bfd6ccbc07ddfd537ca5b968aae79589626 (patch) | |
tree | d2a15c5a4681254c45f750023044a4706be5466c | |
parent | spec: Specify NTP support (diff) | |
download | rtems-central-45237bfd6ccbc07ddfd537ca5b968aae79589626.tar.bz2 |
spec: Improve SMP-specific timecounter validation
-rw-r--r-- | spec/score/timecounter/val/get-smp.yml | 670 |
1 files changed, 603 insertions, 67 deletions
diff --git a/spec/score/timecounter/val/get-smp.yml b/spec/score/timecounter/val/get-smp.yml index d3257d7a..dd09b357 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 |