@@ -383,14 +383,25 @@ static inline bool timespec_normalize(struct timespec *ts)
383
383
384
384
#if defined(CONFIG_SPEED_OPTIMIZATIONS ) && HAS_BUILTIN (__builtin_add_overflow )
385
385
386
+ int64_t sec = 0 ;
386
387
int sign = (ts -> tv_nsec >= 0 ) - (ts -> tv_nsec < 0 );
387
- int64_t sec = (ts -> tv_nsec >= (long )NSEC_PER_SEC ) * (ts -> tv_nsec / (long )NSEC_PER_SEC ) +
388
- ((ts -> tv_nsec < 0 ) && (ts -> tv_nsec != LONG_MIN )) *
389
- DIV_ROUND_UP ((unsigned long )- ts -> tv_nsec , (long )NSEC_PER_SEC ) +
390
- (ts -> tv_nsec == LONG_MIN ) * ((LONG_MAX / NSEC_PER_SEC ) + 1 );
391
- bool overflow = __builtin_add_overflow (ts -> tv_sec , sign * sec , & ts -> tv_sec );
392
388
393
- ts -> tv_nsec -= sign * (long )NSEC_PER_SEC * sec ;
389
+ /* only one of the following should be non-zero */
390
+ sec += (ts -> tv_nsec >= (long )NSEC_PER_SEC ) * (ts -> tv_nsec / (long )NSEC_PER_SEC );
391
+ sec += ((sizeof (ts -> tv_nsec ) != sizeof (int64_t )) && (ts -> tv_nsec != LONG_MIN ) &&
392
+ (ts -> tv_nsec < 0 )) *
393
+ DIV_ROUND_UP ((unsigned long )- ts -> tv_nsec , (long )NSEC_PER_SEC );
394
+ sec += ((sizeof (ts -> tv_nsec ) == sizeof (int64_t )) && (ts -> tv_nsec != INT64_MIN ) &&
395
+ (ts -> tv_nsec < 0 )) *
396
+ DIV_ROUND_UP ((uint64_t )- ts -> tv_nsec , NSEC_PER_SEC );
397
+ sec += ((sizeof (ts -> tv_nsec ) != sizeof (int64_t )) && (ts -> tv_nsec == LONG_MIN )) *
398
+ ((LONG_MAX / NSEC_PER_SEC ) + 1 );
399
+ sec += ((sizeof (ts -> tv_nsec ) == sizeof (int64_t )) && (ts -> tv_nsec == INT64_MIN )) *
400
+ ((INT64_MAX / NSEC_PER_SEC ) + 1 );
401
+
402
+ ts -> tv_nsec -= sec * sign * NSEC_PER_SEC ;
403
+
404
+ bool overflow = __builtin_add_overflow (ts -> tv_sec , sign * sec , & ts -> tv_sec );
394
405
395
406
if (!overflow ) {
396
407
__ASSERT_NO_MSG (timespec_is_valid (ts ));
@@ -405,16 +416,12 @@ static inline bool timespec_normalize(struct timespec *ts)
405
416
if (ts -> tv_nsec >= (long )NSEC_PER_SEC ) {
406
417
sec = ts -> tv_nsec / (long )NSEC_PER_SEC ;
407
418
} else if (ts -> tv_nsec < 0 ) {
408
- if ((sizeof (ts -> tv_nsec ) == sizeof (uint32_t )) && (ts -> tv_nsec == LONG_MIN )) {
409
- sec = DIV_ROUND_UP (LONG_MAX / NSEC_PER_USEC , USEC_PER_SEC );
410
- } else {
411
- sec = DIV_ROUND_UP ((unsigned long )- ts -> tv_nsec , NSEC_PER_SEC );
412
- }
419
+ sec = DIV_ROUND_UP ((unsigned long )- ts -> tv_nsec , NSEC_PER_SEC );
413
420
} else {
414
421
sec = 0 ;
415
422
}
416
423
417
- if ((ts -> tv_nsec < 0 ) && (ts -> tv_sec < 0 ) && (ts -> tv_sec - INT64_MIN < sec )) {
424
+ if ((ts -> tv_nsec < 0 ) && (ts -> tv_sec < 0 ) && (ts -> tv_sec - SYS_TIME_T_MIN < sec )) {
418
425
/*
419
426
* When `tv_nsec` is negative and `tv_sec` is already most negative,
420
427
* further subtraction would cause integer overflow.
@@ -423,7 +430,7 @@ static inline bool timespec_normalize(struct timespec *ts)
423
430
}
424
431
425
432
if ((ts -> tv_nsec >= (long )NSEC_PER_SEC ) && (ts -> tv_sec > 0 ) &&
426
- (INT64_MAX - ts -> tv_sec < sec )) {
433
+ (SYS_TIME_T_MAX - ts -> tv_sec < sec )) {
427
434
/*
428
435
* When `tv_nsec` is >= `NSEC_PER_SEC` and `tv_sec` is already most
429
436
* positive, further addition would cause integer overflow.
@@ -444,7 +451,6 @@ static inline bool timespec_normalize(struct timespec *ts)
444
451
__ASSERT_NO_MSG (timespec_is_valid (ts ));
445
452
446
453
return true;
447
-
448
454
#endif
449
455
}
450
456
@@ -476,12 +482,12 @@ static inline bool timespec_add(struct timespec *a, const struct timespec *b)
476
482
477
483
#else
478
484
479
- if ((a -> tv_sec < 0 ) && (b -> tv_sec < 0 ) && (INT64_MIN - a -> tv_sec > b -> tv_sec )) {
485
+ if ((a -> tv_sec < 0 ) && (b -> tv_sec < 0 ) && (SYS_TIME_T_MIN - a -> tv_sec > b -> tv_sec )) {
480
486
/* negative integer overflow would occur */
481
487
return false;
482
488
}
483
489
484
- if ((a -> tv_sec > 0 ) && (b -> tv_sec > 0 ) && (INT64_MAX - a -> tv_sec < b -> tv_sec )) {
490
+ if ((a -> tv_sec > 0 ) && (b -> tv_sec > 0 ) && (SYS_TIME_T_MAX - a -> tv_sec < b -> tv_sec )) {
485
491
/* positive integer overflow would occur */
486
492
return false;
487
493
}
@@ -517,10 +523,8 @@ static inline bool timespec_negate(struct timespec *ts)
517
523
518
524
#else
519
525
520
- /* note: must check for 32-bit size here until #90029 is resolved */
521
- if (((sizeof (ts -> tv_sec ) == sizeof (int32_t )) && (ts -> tv_sec == INT32_MIN )) ||
522
- ((sizeof (ts -> tv_sec ) == sizeof (int64_t )) && (ts -> tv_sec == INT64_MIN ))) {
523
- /* -INT64_MIN > INT64_MAX, so +ve integer overflow would occur */
526
+ if (ts -> tv_sec == SYS_TIME_T_MIN ) {
527
+ /* -SYS_TIME_T_MIN > SYS_TIME_T_MAX, so positive integer overflow would occur */
524
528
return false;
525
529
}
526
530
@@ -614,123 +618,83 @@ static inline bool timespec_equal(const struct timespec *a, const struct timespe
614
618
* This function converts time durations expressed as Zephyr @ref k_timeout_t
615
619
* objects to `struct timespec` objects.
616
620
*
621
+ * @note This function will assert if assertions are enabled and @p timeout is not relative,
622
+ * (i.e. a timeout generated by `K_TIMEOUT_ABS_TICKS` or similar is used).
623
+ *
617
624
* @param timeout the kernel timeout to convert
618
625
* @param[out] ts the timespec to store the result
619
626
*/
620
627
static inline void timespec_from_timeout (k_timeout_t timeout , struct timespec * ts )
621
628
{
622
629
__ASSERT_NO_MSG (ts != NULL );
623
-
624
- #if defined(CONFIG_SPEED_OPTIMIZATIONS )
625
-
626
- uint64_t ns = k_ticks_to_ns_ceil64 (timeout .ticks );
627
-
628
- * ts = (struct timespec ){
629
- .tv_sec = (timeout .ticks == K_TICKS_FOREVER ) * INT64_MAX +
630
- (timeout .ticks != K_TICKS_FOREVER ) * (ns / NSEC_PER_SEC ),
631
- .tv_nsec = (timeout .ticks == K_TICKS_FOREVER ) * (NSEC_PER_SEC - 1 ) +
632
- (timeout .ticks != K_TICKS_FOREVER ) * (ns % NSEC_PER_SEC ),
633
- };
634
-
635
- #else
636
-
637
- if (timeout .ticks == 0 ) {
638
- /* This is equivalent to K_NO_WAIT, but without including <zephyr/kernel.h> */
639
- ts -> tv_sec = 0 ;
640
- ts -> tv_nsec = 0 ;
641
- } else if (timeout .ticks == K_TICKS_FOREVER ) {
642
- /* This is roughly equivalent to K_FOREVER, but not including <zephyr/kernel.h> */
643
- ts -> tv_sec = (time_t )INT64_MAX ;
644
- ts -> tv_nsec = NSEC_PER_SEC - 1 ;
630
+ __ASSERT_NO_MSG (Z_IS_TIMEOUT_RELATIVE (timeout ) ||
631
+ (IS_ENABLED (CONFIG_TIMEOUT_64BIT ) &&
632
+ K_TIMEOUT_EQ (timeout , (k_timeout_t ){K_TICKS_FOREVER })));
633
+
634
+ /* equivalent of K_FOREVER without including kernel.h */
635
+ if (K_TIMEOUT_EQ (timeout , (k_timeout_t ){K_TICKS_FOREVER })) {
636
+ /* duration == K_TICKS_FOREVER ticks */
637
+ * ts = K_TS_FOREVER ;
638
+ /* equivalent of K_NO_WAIT without including kernel.h */
639
+ } else if (K_TIMEOUT_EQ (timeout , (k_timeout_t ){0 })) {
640
+ /* duration <= 0 ticks */
641
+ * ts = K_TS_NO_WAIT ;
645
642
} else {
646
- uint64_t ns = k_ticks_to_ns_ceil64 (timeout .ticks );
647
-
648
- ts -> tv_sec = ns / NSEC_PER_SEC ;
649
- ts -> tv_nsec = ns - ts -> tv_sec * NSEC_PER_SEC ;
643
+ * ts = K_TICKS_TO_TIMESPEC (timeout .ticks );
650
644
}
651
645
652
- #endif
653
-
654
646
__ASSERT_NO_MSG (timespec_is_valid (ts ));
655
647
}
656
648
657
649
/**
658
650
* @brief Convert a timespec to a kernel timeout
659
651
*
660
- * This function converts durations expressed as a `struct timespec` to Zephyr @ref k_timeout_t
661
- * objects .
652
+ * This function converts a time duration, @p req, expressed as a `timespec` object, to a Zephyr
653
+ * @ref k_timeout_t object .
662
654
*
663
- * Given that the range of a `struct timespec` is much larger than the range of @ref k_timeout_t,
664
- * and also given that the functions are only intended to be used to convert time durations
665
- * (which are always positive), the function will saturate to @ref K_NO_WAIT if the `tv_sec` field
666
- * of @a ts is negative.
655
+ * If @p req contains a negative duration or if both `tv_sec` and `tv_nsec` fields are zero, this
656
+ * function will return @ref K_NO_WAIT.
667
657
*
668
- * Similarly, if the duration is too large to fit in @ref k_timeout_t, the function will
669
- * saturate to @ref K_FOREVER.
658
+ * If @p req contains the maximum representable `timespec`, `{max(time_t), 999999999}`, then this
659
+ * function will return @ref K_FOREVER.
670
660
*
671
- * @param ts the timespec to convert
672
- * @return the kernel timeout
661
+ * If @p req contains a value that is greater than the maximum equivalent tick duration, then this
662
+ * function will return the maximum representable tick duration (i.e. @p req will be rounded-down).
663
+ *
664
+ * Otherwise, this function will return the `k_timeout_t` that is rounded-up to a tick boundary.
665
+ *
666
+ * @param req the requested `timespec` to convert
667
+ * @return the corresponding kernel timeout
673
668
*/
674
- static inline k_timeout_t timespec_to_timeout (const struct timespec * ts )
669
+ static inline k_timeout_t timespec_to_timeout (const struct timespec * req )
675
670
{
676
- __ASSERT_NO_MSG (( ts != NULL ) && timespec_is_valid ( ts )) ;
671
+ k_timeout_t timeout ;
677
672
678
- #if defined(CONFIG_SPEED_OPTIMIZATIONS )
679
-
680
- return (k_timeout_t ){
681
- /* note: must check for 32-bit size here until #90029 is resolved */
682
- .ticks = ((sizeof (ts -> tv_sec ) == sizeof (int32_t ) && (ts -> tv_sec == INT32_MAX ) &&
683
- (ts -> tv_nsec == NSEC_PER_SEC - 1 )) ||
684
- ((sizeof (ts -> tv_sec ) == sizeof (int64_t )) && (ts -> tv_sec == INT64_MAX ) &&
685
- (ts -> tv_nsec == NSEC_PER_SEC - 1 ))) *
686
- K_TICKS_FOREVER +
687
- ((sizeof (ts -> tv_sec ) == sizeof (int32_t ) && (ts -> tv_sec == INT32_MAX ) &&
688
- (ts -> tv_nsec == NSEC_PER_SEC - 1 )) ||
689
- ((sizeof (ts -> tv_sec ) == sizeof (int64_t )) && (ts -> tv_sec != INT64_MAX ) &&
690
- (ts -> tv_sec >= 0 ))) *
691
- (IS_ENABLED (CONFIG_TIMEOUT_64BIT )
692
- ? (int64_t )(CLAMP (
693
- k_sec_to_ticks_floor64 (ts -> tv_sec ) +
694
- k_ns_to_ticks_floor64 (ts -> tv_nsec ),
695
- 0 , (uint64_t )INT64_MAX ))
696
- : (uint32_t )(CLAMP (
697
- k_sec_to_ticks_floor64 (ts -> tv_sec ) +
698
- k_ns_to_ticks_floor64 (ts -> tv_nsec ),
699
- 0 , (uint64_t )UINT32_MAX )))};
673
+ __ASSERT_NO_MSG ((req != NULL ) && timespec_is_valid (req ));
700
674
701
- #else
675
+ if (timespec_compare (req , & K_TS_NO_WAIT ) <= 0 ) {
676
+ /* equivalent of K_NO_WAIT without including kernel.h */
677
+ timeout .ticks = 0 ;
678
+ return timeout ;
679
+ }
702
680
703
- if ((ts -> tv_sec < 0 ) || (ts -> tv_sec == 0 && ts -> tv_nsec == 0 )) {
704
- /* This is equivalent to K_NO_WAIT, but without including <zephyr/kernel.h> */
705
- return (k_timeout_t ){
706
- .ticks = 0 ,
707
- };
708
- /* note: must check for 32-bit size here until #90029 is resolved */
709
- } else if (((sizeof (ts -> tv_sec ) == sizeof (int32_t )) && (ts -> tv_sec == INT32_MAX ) &&
710
- (ts -> tv_nsec == NSEC_PER_SEC - 1 )) ||
711
- ((sizeof (ts -> tv_sec ) == sizeof (int64_t )) && (ts -> tv_sec == INT64_MAX ) &&
712
- (ts -> tv_nsec == NSEC_PER_SEC - 1 ))) {
713
- /* This is equivalent to K_FOREVER, but not including <zephyr/kernel.h> */
714
- return (k_timeout_t ){
715
- .ticks = K_TICKS_FOREVER ,
716
- };
681
+ if (timespec_compare (req , & K_TS_FOREVER ) == 0 ) {
682
+ /* equivalent of K_FOREVER without including kernel.h */
683
+ timeout .ticks = K_TICKS_FOREVER ;
684
+ return timeout ;
685
+ }
686
+
687
+ if (timespec_compare (req , & K_TS_MAX ) >= 0 ) {
688
+ /* round down to align to max ticks */
689
+ timeout .ticks = K_TICK_MAX ;
717
690
} else {
718
- if (IS_ENABLED (CONFIG_TIMEOUT_64BIT )) {
719
- return (k_timeout_t ){
720
- .ticks = (int64_t )CLAMP (k_sec_to_ticks_floor64 (ts -> tv_sec ) +
721
- k_ns_to_ticks_floor64 (ts -> tv_nsec ),
722
- 0 , (uint64_t )INT64_MAX ),
723
- };
724
- } else {
725
- return (k_timeout_t ){
726
- .ticks = (uint32_t )CLAMP (k_sec_to_ticks_floor64 (ts -> tv_sec ) +
727
- k_ns_to_ticks_floor64 (ts -> tv_nsec ),
728
- 0 , (uint64_t )UINT32_MAX ),
729
- };
730
- }
691
+ /* round up to align to next tick boundary */
692
+ timeout .ticks = CLAMP (k_ns_to_ticks_ceil64 (req -> tv_nsec ) +
693
+ k_sec_to_ticks_ceil64 (req -> tv_sec ),
694
+ K_TICK_MIN , K_TICK_MAX );
731
695
}
732
696
733
- #endif
697
+ return timeout ;
734
698
}
735
699
736
700
/**
0 commit comments