Skip to content

Commit 963d5c0

Browse files
committed
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 <cfriedt@tenstorrent.com>
1 parent a455032 commit 963d5c0

File tree

3 files changed

+41
-6
lines changed

3 files changed

+41
-6
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_TS_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_TS_FOREVER) == 0) {
694+
if (rem != NULL) {
695+
*rem = K_TS_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
@@ -175,7 +175,7 @@ int z_impl_sys_clock_nanosleep(int clock_id, int flags, const struct timespec *r
175175
(void)timespec_add(&duration, &rem);
176176
}
177177

178-
timeout = timespec_to_timeout(&duration);
178+
timeout = timespec_to_timeout(&duration, NULL);
179179
end = sys_timepoint_calc(timeout);
180180
do {
181181
(void)k_sleep(timeout);

tests/lib/timespec_util/src/main.c

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -454,12 +454,14 @@ ZTEST(timeutil_api, test_timespec_to_timeout)
454454
ARRAY_FOR_EACH(tospecs, i) {
455455
const struct tospec *const tspec = &tospecs[i];
456456
k_timeout_t actual;
457+
struct timespec tick_ts;
458+
struct timespec rem = {};
457459

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

462-
actual = timespec_to_timeout(&tspec->tspec);
464+
actual = timespec_to_timeout(&tspec->tspec, &rem);
463465
if (tspec->saturation == 0) {
464466
/* exact match or rounding up */
465467
if (!tspec->negative &&
@@ -501,20 +503,32 @@ ZTEST(timeutil_api, test_timespec_to_timeout)
501503
"} are unexpectedly different",
502504
i, (int64_t)actual.ticks, (int64_t)K_TICK_MAX);
503505
}
506+
507+
timespec_from_timeout(tspec->timeout, &tick_ts);
508+
timespec_add(&tick_ts, &rem);
509+
zexpect_true(timespec_equal(&tick_ts, &tspec->tspec),
510+
"%d: {%ld, %ld} and {%ld, %ld} are unexpectedly different", i,
511+
tick_ts.tv_sec, tick_ts.tv_nsec, tspec->tspec.tv_sec,
512+
tspec->tspec.tv_nsec);
504513
}
505514

506515
#if defined(CONFIG_TIMEOUT_64BIT) && (CONFIG_SYS_CLOCK_TICKS_PER_SEC == 100)
507516
{
517+
struct timespec rem = {};
508518
k_timeout_t to = K_TICKS(K_TICK_MAX);
509519
/* K_TS_MAX corresponding K_TICK_MAX with a tick rate of 100 Hz */
510520
struct timespec ts = K_TIMESPEC(92233720368547758LL, 70000000L);
511521

512-
zexpect_true(K_TIMEOUT_EQ(timespec_to_timeout(&ts), to),
522+
zexpect_true(K_TIMEOUT_EQ(timespec_to_timeout(&ts, &rem), to),
513523
"timespec_to_timeout(%lld, %lld) != %lld", (long long)ts.tv_sec,
514524
(long long)ts.tv_nsec, (long long)to.ticks);
525+
zexpect_true(timespec_equal(&rem, &K_TS_NO_WAIT), "non-zero remainder {%lld, %lld}",
526+
(long long)rem.tv_sec, (long long)rem.tv_nsec);
515527

516-
TC_PRINT("timespec_to_timeout():\nts: {%lld, %lld} => to: {%lld}\n",
517-
(long long)ts.tv_sec, (long long)ts.tv_nsec, (long long)to.ticks);
528+
TC_PRINT("timespec_to_timeout():\nts: {%lld, %lld} => to: {%lld}, rem: {%lld, "
529+
"%lld}\n",
530+
(long long)ts.tv_sec, (long long)ts.tv_nsec, (long long)to.ticks,
531+
(long long)rem.tv_sec, (long long)rem.tv_nsec);
518532
}
519533
#endif
520534
}

0 commit comments

Comments
 (0)