Skip to content

sys: timeutil: timspec_to_timeout() provides no deviation for rounded or truncated values #92912

@cfriedt

Description

@cfriedt

Describe the bug

The function timespec_to_timeout() in sys/timeutil.h truncates or rounds input timespec values without providing any indication to the caller or any remainder to indicate how much truncation or rounding occurred.

It's not always the desired behaviour to e.g. round up to the nearest tick boundary, which is the default behaviour. For example, when computing a timeout for sleeping, yes, we generally do want to round up to the next tick boundary (except if it rounds to K_FOREVER). However, when computing a timeout for a deadline for e.g. a GPIO interrupt, we generally want to be more conservative and round down.

Additionally, and most especially for a Real-Time OS, any time there is an approximation of a duration or time point, it's really best practice to provide the error or deviation from the requested value back to the calller. This is quite evident when looking at the very tight time margins that must be captured e.g. in radio stacks, and how time deviations must be accumulated and accounted for for periodic signals.

From my perspective, this is a functional requirement for an RTOS.

  • What target platform are you using? all
  • What have you tried to diagnose or workaround this issue? The workaround is to separately call this after calling timeout = timespec_to_timeout(req)
timespec_from_timeout(timeout, rem);
timespec_sub(rem, req);
timespec_negate(rem);
  • Is this a regression? No

Regression

  • This is a regression.

Steps to reproduce

Steps to reproduce the behaviour:

  1. gh pr checkout 92709
  2. git rebase -i HEAD~2 (switch pick to d to delete the commit 8b9e097)
  3. edit tests/lib/timespec_util/src/main.c and add #define timespec_to_timeout_rem(req, rem) timespec_to_timeout(req)
  4. twister -T tests/lib/timespec_util

Relevant log output

*** Booting Zephyr OS build v4.2.0-rc2-39-gd31c2b6a24f0 ***
Running TESTSUITE timeutil_api
===================================================================
CONFIG_SYS_CLOCK_TICKS_PER_SEC=100
CONFIG_TIMEOUT_64BIT=n
K_TICK_MIN: 1
K_TICK_MAX: 4294967294
K_TS_MIN: {0, 10000000}
K_TS_MAX: {42949672, 940000000}
SYS_TIME_T_MIN: -9223372036854775808
SYS_TIME_T_MAX: 9223372036854775807
===================================================================
START - test_K_TICKS_TO_NSECS
 PASS - test_K_TICKS_TO_NSECS in 0.001 seconds
===================================================================
START - test_K_TICKS_TO_SECS
 PASS - test_K_TICKS_TO_SECS in 0.001 seconds
===================================================================
START - test_timespec_add
 PASS - test_timespec_add in 0.001 seconds
===================================================================
START - test_timespec_compare
 PASS - test_timespec_compare in 0.001 seconds
===================================================================
START - test_timespec_equal
 PASS - test_timespec_equal in 0.001 seconds
===================================================================
START - test_timespec_from_timeout
 PASS - test_timespec_from_timeout in 0.001 seconds
===================================================================
START - test_timespec_is_valid
 PASS - test_timespec_is_valid in 0.001 seconds
===================================================================
START - test_timespec_negate
 PASS - test_timespec_negate in 0.001 seconds
===================================================================
START - test_timespec_normalize
 PASS - test_timespec_normalize in 0.001 seconds
===================================================================
START - test_timespec_sub
 PASS - test_timespec_sub in 0.001 seconds
===================================================================
START - test_timespec_to_timeout

    Expectation failed at WEST_TOPDIR/zephyr/tests/lib/timespec_util/src/main.c:519: timeutil_api_test_timespec_to_timeout: (timespec_equal(&tick_ts, &tspec->tspec) is false)
0: {0, 0} and {0, -2147483648} are unexpectedly different

    Expectation failed at WEST_TOPDIR/zephyr/tests/lib/timespec_util/src/main.c:519: timeutil_api_test_timespec_to_timeout: (timespec_equal(&tick_ts, &tspec->tspec) is false)
1: {0, 0} and {0, -1} are unexpectedly different

    Expectation failed at WEST_TOPDIR/zephyr/tests/lib/timespec_util/src/main.c:519: timeutil_api_test_timespec_to_timeout: (timespec_equal(&tick_ts, &tspec->tspec) is false)
2: {0, 0} and {0, -1} are unexpectedly different

    Expectation failed at WEST_TOPDIR/zephyr/tests/lib/timespec_util/src/main.c:519: timeutil_api_test_timespec_to_timeout: (timespec_equal(&tick_ts, &tspec->tspec) is false)
7: {0, 0} and {10000000, 0} are unexpectedly different

    Expectation failed at WEST_TOPDIR/zephyr/tests/lib/timespec_util/src/main.c:519: timeutil_api_test_timespec_to_timeout: (timespec_equal(&tick_ts, &tspec->tspec) is false)
8: {0, 0} and {10000000, 0} are unexpectedly different

    Expectation failed at WEST_TOPDIR/zephyr/tests/lib/timespec_util/src/main.c:519: timeutil_api_test_timespec_to_timeout: (timespec_equal(&tick_ts, &tspec->tspec) is false)
10: {0, 0} and {10000000, 0} are unexpectedly different

    Expectation failed at WEST_TOPDIR/zephyr/tests/lib/timespec_util/src/main.c:519: timeutil_api_test_timespec_to_timeout: (timespec_equal(&tick_ts, &tspec->tspec) is false)
11: {0, 0} and {10000000, 0} are unexpectedly different

    Expectation failed at WEST_TOPDIR/zephyr/tests/lib/timespec_util/src/main.c:519: timeutil_api_test_timespec_to_timeout: (timespec_equal(&tick_ts, &tspec->tspec) is false)
12: {0, 0} and {10000000, 0} are unexpectedly different

    Expectation failed at WEST_TOPDIR/zephyr/tests/lib/timespec_util/src/main.c:519: timeutil_api_test_timespec_to_timeout: (timespec_equal(&tick_ts, &tspec->tspec) is false)
13: {0, 0} and {20000000, 0} are unexpectedly different

    Expectation failed at WEST_TOPDIR/zephyr/tests/lib/timespec_util/src/main.c:519: timeutil_api_test_timespec_to_timeout: (timespec_equal(&tick_ts, &tspec->tspec) is false)
14: {0, 0} and {20000000, 0} are unexpectedly different

    Expectation failed at WEST_TOPDIR/zephyr/tests/lib/timespec_util/src/main.c:519: timeutil_api_test_timespec_to_timeout: (timespec_equal(&tick_ts, &tspec->tspec) is false)
15: {0, 0} and {20000000, 0} are unexpectedly different

    Expectation failed at WEST_TOPDIR/zephyr/tests/lib/timespec_util/src/main.c:519: timeutil_api_test_timespec_to_timeout: (timespec_equal(&tick_ts, &tspec->tspec) is false)
23: {0, 10} and {0, 0} are unexpectedly different

    Expectation failed at WEST_TOPDIR/zephyr/tests/lib/timespec_util/src/main.c:519: timeutil_api_test_timespec_to_timeout: (timespec_equal(&tick_ts, &tspec->tspec) is false)
24: {0, 10} and {0, 0} are unexpectedly different

    Expectation failed at WEST_TOPDIR/zephyr/tests/lib/timespec_util/src/main.c:519: timeutil_api_test_timespec_to_timeout: (timespec_equal(&tick_ts, &tspec->tspec) is false)
25: {0, 10} and {0, 0} are unexpectedly different

    Expectation failed at WEST_TOPDIR/zephyr/tests/lib/timespec_util/src/main.c:510: timeutil_api_test_timespec_to_timeout: (timespec_equal(&tick_ts, &workaround) is false)
27: {0, 42949672} and {940000000, 0} are unexpectedly different
 FAIL - test_timespec_to_timeout in 0.014 seconds
===================================================================
TESTSUITE timeutil_api failed.

------ TESTSUITE SUMMARY START ------

SUITE FAIL -  90.91% [timeutil_api]: pass = 10, fail = 1, skip = 0, total = 11 duration = 0.024 seconds
 - PASS - [timeutil_api.test_K_TICKS_TO_NSECS] duration = 0.001 seconds
 - PASS - [timeutil_api.test_K_TICKS_TO_SECS] duration = 0.001 seconds
 - PASS - [timeutil_api.test_timespec_add] duration = 0.001 seconds
 - PASS - [timeutil_api.test_timespec_compare] duration = 0.001 seconds
 - PASS - [timeutil_api.test_timespec_equal] duration = 0.001 seconds
 - PASS - [timeutil_api.test_timespec_from_timeout] duration = 0.001 seconds
 - PASS - [timeutil_api.test_timespec_is_valid] duration = 0.001 seconds
 - PASS - [timeutil_api.test_timespec_negate] duration = 0.001 seconds
 - PASS - [timeutil_api.test_timespec_normalize] duration = 0.001 seconds
 - PASS - [timeutil_api.test_timespec_sub] duration = 0.001 seconds
 - FAIL - [timeutil_api.test_timespec_to_timeout] duration = 0.014 seconds

------ TESTSUITE SUMMARY END ------

===================================================================
RunID: d84614d788819d0cd4da2827ca76e1fd
PROJECT EXECUTION FAILED

Impact

Functional Limitation – Some features not working as expected, but system usable.

Environment

  • OS: all
  • Toolchain: Zephyr SDK v0.17.2
  • v4.2.0-rc2

Additional Context

No response

Metadata

Metadata

Assignees

Labels

area: Base OSBase OS Library (lib/os)bugThe issue is a bug, or the PR is fixing a bugpriority: lowLow impact/importance bug

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions