Skip to content

Commit 4ff0593

Browse files
cfriedtkartben
authored andcommitted
sys: timeutil: compute the remainder in timespec to timeout conversion
Since it's possible that rounding up might not always be the right thing to do in every situation, in order to allow the application to make more informed decisions, we created a modified timespec_to_timeout() that also returns the remainder (or difference) between the requested time to convert and resulting k_timeout_t. The difference is expressed as a timespec object. Signed-off-by: Chris Friedt <[email protected]>
1 parent fd41e08 commit 4ff0593

File tree

3 files changed

+43
-7
lines changed

3 files changed

+43
-7
lines changed

include/zephyr/sys/timeutil.h

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -663,22 +663,37 @@ static inline void timespec_from_timeout(k_timeout_t timeout, struct timespec *t
663663
*
664664
* Otherwise, this function will return the `k_timeout_t` that is rounded-up to a tick boundary.
665665
*
666+
* If @p rem is not `NULL`, it will be set to the remainder of the conversion, i.e. the difference
667+
* between the requested duration and the converted duration as a `timespec` object, approximately
668+
* as shown below.
669+
*
670+
* ```python
671+
* rem = requested_duration - converted_duration
672+
* ```
673+
*
666674
* @param req the requested `timespec` to convert
675+
* @param[out] rem optional pointer to a `timespec` to store the remainder
667676
* @return the corresponding kernel timeout
668677
*/
669-
static inline k_timeout_t timespec_to_timeout(const struct timespec *req)
678+
static inline k_timeout_t timespec_to_timeout(const struct timespec *req, struct timespec *rem)
670679
{
671680
k_timeout_t timeout;
672681

673682
__ASSERT_NO_MSG((req != NULL) && timespec_is_valid(req));
674683

675684
if (timespec_compare(req, &K_TIMESPEC_NO_WAIT) <= 0) {
685+
if (rem != NULL) {
686+
*rem = *req;
687+
}
676688
/* equivalent of K_NO_WAIT without including kernel.h */
677689
timeout.ticks = 0;
678690
return timeout;
679691
}
680692

681693
if (timespec_compare(req, &K_TIMESPEC_FOREVER) == 0) {
694+
if (rem != NULL) {
695+
*rem = K_TIMESPEC_NO_WAIT;
696+
}
682697
/* equivalent of K_FOREVER without including kernel.h */
683698
timeout.ticks = K_TICKS_FOREVER;
684699
return timeout;
@@ -694,6 +709,12 @@ static inline k_timeout_t timespec_to_timeout(const struct timespec *req)
694709
K_TICK_MIN, K_TICK_MAX);
695710
}
696711

712+
if (rem != NULL) {
713+
timespec_from_timeout(timeout, rem);
714+
timespec_sub(rem, req);
715+
timespec_negate(rem);
716+
}
717+
697718
return timeout;
698719
}
699720

lib/os/clock.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ int z_impl_sys_clock_nanosleep(int clock_id, int flags, const struct timespec *r
192192
(void)timespec_add(&duration, &rem);
193193
}
194194

195-
timeout = timespec_to_timeout(&duration);
195+
timeout = timespec_to_timeout(&duration, NULL);
196196
end = sys_timepoint_calc(timeout);
197197
do {
198198
(void)k_sleep(timeout);

tests/lib/timespec_util/src/main.c

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -455,12 +455,14 @@ ZTEST(timeutil_api, test_timespec_to_timeout)
455455
ARRAY_FOR_EACH(tospecs, i) {
456456
const struct tospec *const tspec = &tospecs[i];
457457
k_timeout_t actual;
458+
struct timespec tick_ts;
459+
struct timespec rem = {};
458460

459461
TC_PRINT("%zu: ticks: {%lld}, timespec: {%lld, %lld}\n", i,
460462
(long long)tspec->timeout.ticks, (long long)tspec->tspec.tv_sec,
461463
(long long)tspec->tspec.tv_nsec);
462464

463-
actual = timespec_to_timeout(&tspec->tspec);
465+
actual = timespec_to_timeout(&tspec->tspec, &rem);
464466
if (tspec->saturation == 0) {
465467
/* exact match or rounding up */
466468
if (!tspec->negative &&
@@ -508,20 +510,33 @@ ZTEST(timeutil_api, test_timespec_to_timeout)
508510
"} are unexpectedly different",
509511
i, (int64_t)actual.ticks, (int64_t)K_TICK_MAX);
510512
}
513+
514+
timespec_from_timeout(tspec->timeout, &tick_ts);
515+
timespec_add(&tick_ts, &rem);
516+
zexpect_true(timespec_equal(&tick_ts, &tspec->tspec),
517+
"%d: {%ld, %ld} and {%ld, %ld} are unexpectedly different", i,
518+
tick_ts.tv_sec, tick_ts.tv_nsec, tspec->tspec.tv_sec,
519+
tspec->tspec.tv_nsec);
511520
}
512521

513522
#if defined(CONFIG_TIMEOUT_64BIT) && (CONFIG_SYS_CLOCK_TICKS_PER_SEC == 100)
514523
{
524+
struct timespec rem = {};
515525
k_timeout_t to = K_TICKS(K_TICK_MAX);
516526
/* K_TIMESPEC_MAX corresponding K_TICK_MAX with a tick rate of 100 Hz */
517527
struct timespec ts = K_TIMESPEC(92233720368547758LL, 70000000L);
518528

519-
zexpect_true(K_TIMEOUT_EQ(timespec_to_timeout(&ts), to),
529+
zexpect_true(K_TIMEOUT_EQ(timespec_to_timeout(&ts, &rem), to),
520530
"timespec_to_timeout(%lld, %lld) != %lld", (long long)ts.tv_sec,
521531
(long long)ts.tv_nsec, (long long)to.ticks);
522-
523-
TC_PRINT("timespec_to_timeout():\nts: {%lld, %lld} => to: {%lld}\n",
524-
(long long)ts.tv_sec, (long long)ts.tv_nsec, (long long)to.ticks);
532+
zexpect_true(timespec_equal(&rem, &K_TIMESPEC_NO_WAIT),
533+
"non-zero remainder {%lld, %lld}", (long long)rem.tv_sec,
534+
(long long)rem.tv_nsec);
535+
536+
TC_PRINT("timespec_to_timeout():\nts: {%lld, %lld} => to: {%lld}, rem: {%lld, "
537+
"%lld}\n",
538+
(long long)ts.tv_sec, (long long)ts.tv_nsec, (long long)to.ticks,
539+
(long long)rem.tv_sec, (long long)rem.tv_nsec);
525540
}
526541
#endif
527542
}

0 commit comments

Comments
 (0)