Skip to content

Commit 5aaaeb7

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 f7a2080 commit 5aaaeb7

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
@@ -453,12 +453,14 @@ ZTEST(timeutil_api, test_timespec_to_timeout)
453453
ARRAY_FOR_EACH(tospecs, i) {
454454
const struct tospec *const tspec = &tospecs[i];
455455
k_timeout_t actual;
456+
struct timespec tick_ts;
457+
struct timespec rem = {};
456458

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

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

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

511-
zexpect_true(K_TIMEOUT_EQ(timespec_to_timeout(&ts), to),
521+
zexpect_true(K_TIMEOUT_EQ(timespec_to_timeout(&ts, &rem), to),
512522
"timespec_to_timeout(%lld, %lld) != %lld", (long long)ts.tv_sec,
513523
(long long)ts.tv_nsec, (long long)to.ticks);
524+
zexpect_true(timespec_equal(&rem, &K_TS_NO_WAIT), "non-zero remainder {%lld, %lld}",
525+
(long long)rem.tv_sec, (long long)rem.tv_nsec);
514526

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

0 commit comments

Comments
 (0)