File indexing completed on 2025-05-11 08:24:53
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051 #ifdef HAVE_CONFIG_H
0052 #include "config.h"
0053 #endif
0054
0055 #include <rtems.h>
0056 #include <rtems/counter.h>
0057 #include <rtems/timecounter.h>
0058 #include <rtems/score/smpbarrier.h>
0059 #include <rtems/score/threaddispatch.h>
0060
0061 #include "tx-support.h"
0062
0063 #include <rtems/test.h>
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165 typedef struct {
0166 struct timecounter base;
0167 Atomic_Ulong counter;
0168 Atomic_Uint *generation_0;
0169 Atomic_Uint *generation_1;
0170 SMP_barrier_Control barrier;
0171 SMP_barrier_State barrier_state[ 2 ];
0172 } Timecounter;
0173
0174 static Timecounter test_timecounter;
0175
0176 static uint32_t GetTimecount( struct timecounter *base )
0177 {
0178 Timecounter *tc;
0179
0180 tc = (Timecounter *) base;
0181
0182 return (uint32_t) _Atomic_Fetch_add_ulong(
0183 &tc->counter,
0184 1,
0185 ATOMIC_ORDER_RELAXED
0186 );
0187 }
0188
0189 static uint32_t GetTimecountBarrier( struct timecounter *base )
0190 {
0191 Timecounter *tc;
0192
0193 tc = (Timecounter *) base;
0194
0195
0196 _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 0 ], 2 );
0197
0198
0199 _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 0 ], 2 );
0200
0201 return GetTimecount( &tc->base );
0202 }
0203
0204 static uint32_t GetCounter( const Timecounter *tc )
0205 {
0206 return (uint32_t) _Atomic_Load_ulong(
0207 &tc->counter,
0208 ATOMIC_ORDER_RELAXED
0209 );
0210 }
0211
0212 static void SetCounter( Timecounter *tc, uint32_t counter )
0213 {
0214 _Atomic_Store_ulong(
0215 &tc->counter,
0216 counter,
0217 ATOMIC_ORDER_RELAXED
0218 );
0219 }
0220
0221 static void CallTimecounterTick( void )
0222 {
0223 Per_CPU_Control *cpu_self;
0224
0225 cpu_self = _Thread_Dispatch_disable();
0226 rtems_timecounter_tick();
0227 _Thread_Dispatch_enable( cpu_self );
0228 }
0229
0230 static void SetGeneration( Timecounter *tc, unsigned int generation )
0231 {
0232 _Atomic_Store_uint( tc->generation_0, generation, ATOMIC_ORDER_RELAXED );
0233 _Atomic_Store_uint( tc->generation_1, generation, ATOMIC_ORDER_RELAXED );
0234 }
0235
0236 static void PrepareSynchronousWork( Timecounter *tc )
0237 {
0238
0239 _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 0 ], 2 );
0240
0241 SetCounter( tc, 0 );
0242
0243
0244 _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 0 ], 2 );
0245 }
0246
0247 static void CleanupSynchronousWork( Timecounter *tc )
0248 {
0249
0250 _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 0 ], 2 );
0251
0252 T_eq_u32( GetCounter( tc ), 3 );
0253 }
0254
0255 static void SynchronousWorker( rtems_task_argument arg )
0256 {
0257 Timecounter *tc;
0258
0259 tc = (Timecounter *) arg;
0260
0261 while ( true ) {
0262
0263 _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 );
0264
0265 SetGeneration( tc, 0 );
0266
0267
0268 _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 );
0269
0270
0271 _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 );
0272
0273 SetGeneration( tc, 1 );
0274
0275
0276 _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 );
0277
0278
0279 _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 );
0280
0281 SetGeneration( tc, 2 );
0282
0283
0284 _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 );
0285
0286
0287 _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 );
0288
0289
0290 _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 );
0291
0292
0293 _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 );
0294 }
0295 }
0296
0297 static void PrepareZeroWork( Timecounter *tc )
0298 {
0299
0300 _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 0 ], 2 );
0301
0302 SetCounter( tc, 0 );
0303
0304
0305 _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 0 ], 2 );
0306 }
0307
0308 static void CleanupZeroWork( Timecounter *tc )
0309 {
0310
0311 _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 0 ], 2 );
0312
0313 T_eq_u32( GetCounter( tc ), 0 );
0314 }
0315
0316 static void ZeroWorker( rtems_task_argument arg )
0317 {
0318 Timecounter *tc;
0319
0320 tc = (Timecounter *) arg;
0321
0322 while ( true ) {
0323
0324 _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 );
0325
0326 SetGeneration( tc, 0 );
0327
0328
0329 _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 );
0330
0331 rtems_counter_delay_nanoseconds( 10000000 );
0332 SetGeneration( tc, 1 );
0333
0334
0335 _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 );
0336 }
0337 }
0338
0339 static void PrepareChangeWork( Timecounter *tc )
0340 {
0341
0342 _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 0 ], 2 );
0343
0344 SetCounter( tc, 0 );
0345
0346
0347 _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 0 ], 2 );
0348 }
0349
0350 static void CleanupChangeWork( Timecounter *tc )
0351 {
0352
0353 _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 0 ], 2 );
0354
0355 T_eq_u32( GetCounter( tc ), 0 );
0356 }
0357
0358 static void ChangeWorker( rtems_task_argument arg )
0359 {
0360 Timecounter *tc;
0361
0362 tc = (Timecounter *) arg;
0363
0364 while ( true ) {
0365 unsigned int i;
0366
0367
0368 _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 );
0369
0370
0371 _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 );
0372
0373 for ( i = 1; i < 1000; ++i ) {
0374 SetGeneration( tc, i );
0375 }
0376
0377
0378 _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 );
0379 }
0380 }
0381
0382
0383 struct timehands {
0384 struct timecounter *th_counter;
0385 int64_t th_adjustment;
0386 uint64_t th_scale;
0387 uint32_t th_large_delta;
0388 uint32_t th_offset_count;
0389 struct bintime th_offset;
0390 struct bintime th_bintime;
0391 struct timeval th_microtime;
0392 struct timespec th_nanotime;
0393 struct bintime th_boottime;
0394 Atomic_Uint th_generation;
0395 struct timehands *th_next;
0396 };
0397
0398 static void NtpUpdateSecond( int64_t *adjustment, time_t *newsec )
0399 {
0400 Timecounter *tc;
0401 struct timehands *th;
0402
0403 tc = &test_timecounter;
0404 th = RTEMS_CONTAINER_OF( adjustment, struct timehands, th_adjustment );
0405 T_assert_eq_ptr( th, th->th_next->th_next );
0406 tc->generation_0 = &th->th_generation;
0407 tc->generation_1 = &th->th_next->th_generation;
0408 }
0409
0410
0411
0412
0413 static void ScoreTimecounterValGetSmp_Action_0( void )
0414 {
0415 Timecounter *tc;
0416 rtems_id worker_id;
0417 struct bintime bt;
0418 sbintime_t sbt;
0419 struct timespec ts;
0420 struct timeval tv;
0421 unsigned int i;
0422
0423 tc = &test_timecounter;
0424 tc->base.tc_get_timecount = GetTimecount;
0425 tc->base.tc_counter_mask = 0xffffffff;
0426 tc->base.tc_frequency = 0x10000000;
0427 tc->base.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
0428 rtems_timecounter_install( &tc->base );
0429
0430 SetCounter( tc, tc->base.tc_frequency );
0431 _Timecounter_Set_NTP_update_second( NtpUpdateSecond );
0432 CallTimecounterTick();
0433 _Timecounter_Set_NTP_update_second( NULL );
0434
0435 T_assert_not_null( tc->generation_0 );
0436 T_assert_not_null( tc->generation_1 );
0437
0438 _SMP_barrier_Control_initialize( &tc->barrier );
0439 _SMP_barrier_State_initialize( &tc->barrier_state[ 0 ] );
0440 _SMP_barrier_State_initialize( &tc->barrier_state[ 1 ] );
0441
0442 worker_id = CreateTask( "WORK", PRIO_NORMAL );
0443 SetScheduler( worker_id, SCHEDULER_B_ID, PRIO_NORMAL );
0444 StartTask( worker_id, SynchronousWorker, tc );
0445
0446 tc->base.tc_get_timecount = GetTimecountBarrier;
0447
0448
0449
0450
0451
0452 PrepareSynchronousWork( tc );
0453 rtems_clock_get_realtime( &ts );
0454 T_eq_i64( ts.tv_sec, 567993616 );
0455 T_eq_long( ts.tv_nsec, 7 );
0456 CleanupSynchronousWork( tc );
0457
0458
0459
0460
0461
0462 PrepareSynchronousWork( tc );
0463 rtems_clock_get_realtime_bintime( &bt );
0464 T_eq_i64( bt.sec, 567993616 );
0465 T_eq_u64( bt.frac, 137438953472 );
0466 CleanupSynchronousWork( tc );
0467
0468
0469
0470
0471
0472 PrepareSynchronousWork( tc );
0473 rtems_clock_get_realtime_timeval( &tv );
0474 T_eq_i64( tv.tv_sec, 567993616 );
0475 T_eq_long( tv.tv_usec, 0 );
0476 CleanupSynchronousWork( tc );
0477
0478
0479
0480
0481
0482 PrepareSynchronousWork( tc );
0483 rtems_clock_get_monotonic( &ts );
0484 T_eq_i64( ts.tv_sec, 17 );
0485 T_eq_long( ts.tv_nsec, 7 );
0486 CleanupSynchronousWork( tc );
0487
0488
0489
0490
0491
0492 PrepareSynchronousWork( tc );
0493 rtems_clock_get_monotonic_bintime( &bt );
0494 T_eq_i64( bt.sec, 17 );
0495 T_eq_u64( bt.frac, 137438953472 );
0496 CleanupSynchronousWork( tc );
0497
0498
0499
0500
0501
0502 PrepareSynchronousWork( tc );
0503 sbt = rtems_clock_get_monotonic_sbintime();
0504 T_eq_i64( sbt, 73014444064 );
0505 CleanupSynchronousWork( tc );
0506
0507
0508
0509
0510
0511 PrepareSynchronousWork( tc );
0512 rtems_clock_get_monotonic_timeval( &tv );
0513 T_eq_i64( tv.tv_sec, 17 );
0514 T_eq_long( tv.tv_usec, 0 );
0515 CleanupSynchronousWork( tc );
0516
0517
0518
0519
0520
0521 tc->base.tc_get_timecount = GetTimecount;
0522 DeleteTask( worker_id );
0523
0524 _SMP_barrier_Control_initialize( &tc->barrier );
0525 _SMP_barrier_State_initialize( &tc->barrier_state[ 0 ] );
0526 _SMP_barrier_State_initialize( &tc->barrier_state[ 1 ] );
0527
0528 worker_id = CreateTask( "WORK", PRIO_NORMAL );
0529 SetScheduler( worker_id, SCHEDULER_B_ID, PRIO_NORMAL );
0530 StartTask( worker_id, ZeroWorker, tc );
0531
0532
0533
0534
0535
0536 PrepareZeroWork( tc );
0537 rtems_clock_get_realtime_coarse( &ts );
0538 CleanupZeroWork( tc );
0539
0540
0541
0542
0543
0544 PrepareZeroWork( tc );
0545 rtems_clock_get_realtime_coarse_bintime( &bt );
0546 CleanupZeroWork( tc );
0547
0548
0549
0550
0551
0552 PrepareZeroWork( tc );
0553 rtems_clock_get_realtime_coarse_timeval( &tv );
0554 CleanupZeroWork( tc );
0555
0556
0557
0558
0559
0560 PrepareZeroWork( tc );
0561 rtems_clock_get_monotonic_coarse( &ts );
0562 CleanupZeroWork( tc );
0563
0564
0565
0566
0567
0568 PrepareZeroWork( tc );
0569 rtems_clock_get_monotonic_coarse_bintime( &bt );
0570 CleanupZeroWork( tc );
0571
0572
0573
0574
0575
0576 PrepareZeroWork( tc );
0577 rtems_clock_get_monotonic_coarse_timeval( &tv );
0578 CleanupZeroWork( tc );
0579
0580
0581
0582
0583
0584 PrepareZeroWork( tc );
0585 rtems_clock_get_boot_time( &ts );
0586 CleanupZeroWork( tc );
0587
0588
0589
0590
0591
0592 PrepareZeroWork( tc );
0593 rtems_clock_get_boot_time_bintime( &bt );
0594 CleanupZeroWork( tc );
0595
0596
0597
0598
0599
0600 PrepareZeroWork( tc );
0601 rtems_clock_get_boot_time_timeval( &tv );
0602 CleanupZeroWork( tc );
0603
0604
0605
0606
0607
0608 DeleteTask( worker_id );
0609
0610 _SMP_barrier_Control_initialize( &tc->barrier );
0611 _SMP_barrier_State_initialize( &tc->barrier_state[ 0 ] );
0612 _SMP_barrier_State_initialize( &tc->barrier_state[ 1 ] );
0613
0614 worker_id = CreateTask( "WORK", PRIO_NORMAL );
0615 SetScheduler( worker_id, SCHEDULER_B_ID, PRIO_NORMAL );
0616 StartTask( worker_id, ChangeWorker, tc );
0617
0618
0619
0620
0621
0622 PrepareChangeWork( tc );
0623
0624 for ( i = 0; i < 100; ++i ) {
0625 rtems_clock_get_realtime_coarse( &ts );
0626 }
0627
0628 CleanupChangeWork( tc );
0629
0630
0631
0632
0633
0634 PrepareChangeWork( tc );
0635
0636 for ( i = 0; i < 100; ++i ) {
0637 rtems_clock_get_realtime_coarse_bintime( &bt );
0638 }
0639
0640 CleanupChangeWork( tc );
0641
0642
0643
0644
0645
0646 PrepareChangeWork( tc );
0647
0648 for ( i = 0; i < 100; ++i ) {
0649 rtems_clock_get_realtime_coarse_timeval( &tv );
0650 }
0651
0652 CleanupChangeWork( tc );
0653
0654
0655
0656
0657
0658 PrepareChangeWork( tc );
0659
0660 for ( i = 0; i < 100; ++i ) {
0661 rtems_clock_get_monotonic_coarse( &ts );
0662 }
0663
0664 CleanupChangeWork( tc );
0665
0666
0667
0668
0669
0670 PrepareChangeWork( tc );
0671
0672 for ( i = 0; i < 100; ++i ) {
0673 rtems_clock_get_monotonic_coarse_bintime( &bt );
0674 }
0675
0676 CleanupChangeWork( tc );
0677
0678
0679
0680
0681
0682 PrepareChangeWork( tc );
0683
0684 for ( i = 0; i < 100; ++i ) {
0685 rtems_clock_get_monotonic_coarse_timeval( &tv );
0686 }
0687
0688 CleanupChangeWork( tc );
0689
0690
0691
0692
0693
0694 PrepareChangeWork( tc );
0695
0696 for ( i = 0; i < 100; ++i ) {
0697 rtems_clock_get_boot_time( &ts );
0698 }
0699
0700 CleanupChangeWork( tc );
0701
0702
0703
0704
0705
0706 PrepareChangeWork( tc );
0707
0708 for ( i = 0; i < 100; ++i ) {
0709 rtems_clock_get_boot_time_bintime( &bt );
0710 }
0711
0712 CleanupChangeWork( tc );
0713
0714
0715
0716
0717
0718 PrepareChangeWork( tc );
0719
0720 for ( i = 0; i < 100; ++i ) {
0721 rtems_clock_get_boot_time_timeval( &tv );
0722 }
0723
0724 CleanupChangeWork( tc );
0725
0726
0727
0728
0729 DeleteTask( worker_id );
0730 }
0731
0732
0733
0734
0735 T_TEST_CASE( ScoreTimecounterValGetSmp )
0736 {
0737 ScoreTimecounterValGetSmp_Action_0();
0738 }
0739
0740