Zephyr Project API 4.2.99
A Scalable Open Source RTOS
Loading...
Searching...
No Matches
timeutil.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2019 Peter Bigot Consulting, LLC
3 * Copyright (c) 2025 Tenstorrent AI ULC
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
22#ifndef ZEPHYR_INCLUDE_SYS_TIMEUTIL_H_
23#define ZEPHYR_INCLUDE_SYS_TIMEUTIL_H_
24
25#include <limits.h>
26#include <stdbool.h>
27#include <stddef.h>
28#include <stdint.h>
29#include <time.h>
30
31#include <zephyr/sys_clock.h>
32#include <zephyr/sys/__assert.h>
35#include <zephyr/sys/util.h>
36#include <zephyr/toolchain.h>
37#include <zephyr/types.h>
38
39#ifdef __cplusplus
40extern "C" {
41#endif
42
43/* Maximum and minimum value TIME_T can hold */
44#define SYS_TIME_T_MAX ((((time_t)1 << (8 * sizeof(time_t) - 2)) - 1) * 2 + 1)
45#define SYS_TIME_T_MIN (-SYS_TIME_T_MAX - 1)
46
47/* Converts ticks to seconds, discarding any fractional seconds */
48#define SYS_TICKS_TO_SECS(ticks) \
49 (((uint64_t)(ticks) >= (uint64_t)K_TICKS_FOREVER) ? SYS_TIME_T_MAX \
50 : k_ticks_to_sec_floor64(ticks))
51
52/* Converts ticks to nanoseconds, modulo NSEC_PER_SEC */
53#define SYS_TICKS_TO_NSECS(ticks) \
54 (((uint64_t)(ticks) >= (uint64_t)K_TICKS_FOREVER) \
55 ? (NSEC_PER_SEC - 1) \
56 : k_ticks_to_ns_floor32((uint64_t)(ticks) % CONFIG_SYS_CLOCK_TICKS_PER_SEC))
57
58/* Define a timespec */
59#define SYS_TIMESPEC(sec, nsec) \
60 ((struct timespec){ \
61 .tv_sec = (time_t)CLAMP((int64_t)(sec), SYS_TIME_T_MIN, SYS_TIME_T_MAX), \
62 .tv_nsec = (long)(nsec), \
63 })
64
65/* Initialize a struct timespec object from a tick count */
66#define SYS_TICKS_TO_TIMESPEC(ticks) SYS_TIMESPEC(SYS_TICKS_TO_SECS(ticks), \
67 SYS_TICKS_TO_NSECS(ticks))
68
69/* The semantic equivalent of K_NO_WAIT but expressed as a timespec object*/
70#define SYS_TIMESPEC_NO_WAIT SYS_TICKS_TO_TIMESPEC(0)
71
72/* The semantic equivalent of K_TICK_MIN but expressed as a timespec object */
73#define SYS_TIMESPEC_MIN SYS_TICKS_TO_TIMESPEC(K_TICK_MIN)
74
75/* The semantic equivalent of K_TICK_MAX but expressed as a timespec object */
76#define SYS_TIMESPEC_MAX SYS_TICKS_TO_TIMESPEC(K_TICK_MAX)
77
78/* The semantic equivalent of K_FOREVER but expressed as a timespec object*/
79#define SYS_TIMESPEC_FOREVER SYS_TIMESPEC(SYS_TIME_T_MAX, NSEC_PER_SEC - 1)
80
89/* Base Year value use in calculations in "timeutil_timegm64" API */
90#define TIME_UTILS_BASE_YEAR 1900
91
102
115
158
180
221
240 const struct timeutil_sync_instant *inst);
241
267 const struct timeutil_sync_instant *base);
268
283
307 uint64_t local, uint64_t *refp);
308
331 uint64_t ref, int64_t *localp);
332
352
375static inline bool timespec_is_valid(const struct timespec *ts)
376{
377 __ASSERT_NO_MSG(ts != NULL);
378
379 return (ts->tv_nsec >= 0) && (ts->tv_nsec < (long)NSEC_PER_SEC);
380}
381
418static inline bool timespec_normalize(struct timespec *ts)
419{
420 __ASSERT_NO_MSG(ts != NULL);
421
422#if defined(CONFIG_SPEED_OPTIMIZATIONS) && HAS_BUILTIN(__builtin_add_overflow)
423
424 int64_t sec = 0;
425 int sign = (ts->tv_nsec >= 0) - (ts->tv_nsec < 0);
426
427 /* only one of the following should be non-zero */
428 sec += (ts->tv_nsec >= (long)NSEC_PER_SEC) * (ts->tv_nsec / (long)NSEC_PER_SEC);
429 sec += ((sizeof(ts->tv_nsec) != sizeof(int64_t)) && (ts->tv_nsec != LONG_MIN) &&
430 (ts->tv_nsec < 0)) *
431 DIV_ROUND_UP((unsigned long)-ts->tv_nsec, (long)NSEC_PER_SEC);
432 sec += ((sizeof(ts->tv_nsec) == sizeof(int64_t)) && (ts->tv_nsec != INT64_MIN) &&
433 (ts->tv_nsec < 0)) *
435 sec += ((sizeof(ts->tv_nsec) != sizeof(int64_t)) && (ts->tv_nsec == LONG_MIN)) *
436 ((LONG_MAX / NSEC_PER_SEC) + 1);
437 sec += ((sizeof(ts->tv_nsec) == sizeof(int64_t)) && (ts->tv_nsec == INT64_MIN)) *
438 ((INT64_MAX / NSEC_PER_SEC) + 1);
439
440 ts->tv_nsec -= sec * sign * NSEC_PER_SEC;
441
442 bool overflow = __builtin_add_overflow(ts->tv_sec, sign * sec, &ts->tv_sec);
443
444 if (!overflow) {
445 __ASSERT_NO_MSG(timespec_is_valid(ts));
446 }
447
448 return !overflow;
449
450#else
451
452 long sec;
453
454 if (ts->tv_nsec >= (long)NSEC_PER_SEC) {
455 sec = ts->tv_nsec / (long)NSEC_PER_SEC;
456 } else if (ts->tv_nsec < 0) {
457 sec = DIV_ROUND_UP((unsigned long)-ts->tv_nsec, NSEC_PER_SEC);
458 } else {
459 sec = 0;
460 }
461
462 if ((ts->tv_nsec < 0) && (ts->tv_sec < 0) && (ts->tv_sec - SYS_TIME_T_MIN < sec)) {
463 /*
464 * When `tv_nsec` is negative and `tv_sec` is already most negative,
465 * further subtraction would cause integer overflow.
466 */
467 return false;
468 }
469
470 if ((ts->tv_nsec >= (long)NSEC_PER_SEC) && (ts->tv_sec > 0) &&
471 (SYS_TIME_T_MAX - ts->tv_sec < sec)) {
472 /*
473 * When `tv_nsec` is >= `NSEC_PER_SEC` and `tv_sec` is already most
474 * positive, further addition would cause integer overflow.
475 */
476 return false;
477 }
478
479 if (ts->tv_nsec >= (long)NSEC_PER_SEC) {
480 ts->tv_sec += sec;
481 ts->tv_nsec -= sec * (long)NSEC_PER_SEC;
482 } else if (ts->tv_nsec < 0) {
483 ts->tv_sec -= sec;
484 ts->tv_nsec += sec * (long)NSEC_PER_SEC;
485 } else {
486 /* no change: SonarQube was complaining */
487 }
488
489 __ASSERT_NO_MSG(timespec_is_valid(ts));
490
491 return true;
492#endif
493}
494
510static inline bool timespec_add(struct timespec *a, const struct timespec *b)
511{
512 __ASSERT_NO_MSG((a != NULL) && timespec_is_valid(a));
513 __ASSERT_NO_MSG((b != NULL) && timespec_is_valid(b));
514
515#if defined(CONFIG_SPEED_OPTIMIZATIONS) && HAS_BUILTIN(__builtin_add_overflow)
516
517 return !__builtin_add_overflow(a->tv_sec, b->tv_sec, &a->tv_sec) &&
518 !__builtin_add_overflow(a->tv_nsec, b->tv_nsec, &a->tv_nsec) &&
520
521#else
522
523 if ((a->tv_sec < 0) && (b->tv_sec < 0) && (SYS_TIME_T_MIN - a->tv_sec > b->tv_sec)) {
524 /* negative integer overflow would occur */
525 return false;
526 }
527
528 if ((a->tv_sec > 0) && (b->tv_sec > 0) && (SYS_TIME_T_MAX - a->tv_sec < b->tv_sec)) {
529 /* positive integer overflow would occur */
530 return false;
531 }
532
533 a->tv_sec += b->tv_sec;
534 a->tv_nsec += b->tv_nsec;
535
536 return timespec_normalize(a);
537
538#endif
539}
540
553static inline bool timespec_negate(struct timespec *ts)
554{
555 __ASSERT_NO_MSG((ts != NULL) && timespec_is_valid(ts));
556
557#if defined(CONFIG_SPEED_OPTIMIZATIONS) && HAS_BUILTIN(__builtin_sub_overflow)
558
559 return !__builtin_sub_overflow(0LL, ts->tv_sec, &ts->tv_sec) &&
560 !__builtin_sub_overflow(0L, ts->tv_nsec, &ts->tv_nsec) && timespec_normalize(ts);
561
562#else
563
564 if (ts->tv_sec == SYS_TIME_T_MIN) {
565 /* -SYS_TIME_T_MIN > SYS_TIME_T_MAX, so positive integer overflow would occur */
566 return false;
567 }
568
569 ts->tv_sec = -ts->tv_sec;
570 ts->tv_nsec = -ts->tv_nsec;
571
572 return timespec_normalize(ts);
573
574#endif
575}
576
592static inline bool timespec_sub(struct timespec *a, const struct timespec *b)
593{
594 __ASSERT_NO_MSG(a != NULL);
595 __ASSERT_NO_MSG(b != NULL);
596
597 struct timespec neg = *b;
598
599 return timespec_negate(&neg) && timespec_add(a, &neg);
600}
601
614static inline int timespec_compare(const struct timespec *a, const struct timespec *b)
615{
616 __ASSERT_NO_MSG((a != NULL) && timespec_is_valid(a));
617 __ASSERT_NO_MSG((b != NULL) && timespec_is_valid(b));
618
619 return (((a->tv_sec == b->tv_sec) && (a->tv_nsec < b->tv_nsec)) * -1) +
620 (((a->tv_sec == b->tv_sec) && (a->tv_nsec > b->tv_nsec)) * 1) +
621 ((a->tv_sec < b->tv_sec) * -1) + ((a->tv_sec > b->tv_sec));
622}
623
636static inline bool timespec_equal(const struct timespec *a, const struct timespec *b)
637{
638 __ASSERT_NO_MSG(a != NULL);
639 __ASSERT_NO_MSG(b != NULL);
640
641 return (a->tv_sec == b->tv_sec) && (a->tv_nsec == b->tv_nsec);
642}
643
665static inline void timespec_from_timeout(k_timeout_t timeout, struct timespec *ts)
666{
667 __ASSERT_NO_MSG(ts != NULL);
668 __ASSERT_NO_MSG(Z_IS_TIMEOUT_RELATIVE(timeout) ||
669 (IS_ENABLED(CONFIG_TIMEOUT_64BIT) &&
671
672 /* equivalent of K_FOREVER without including kernel.h */
673 if (K_TIMEOUT_EQ(timeout, (k_timeout_t){K_TICKS_FOREVER})) {
674 /* duration == K_TICKS_FOREVER ticks */
676 /* equivalent of K_NO_WAIT without including kernel.h */
677 } else if (K_TIMEOUT_EQ(timeout, (k_timeout_t){0})) {
678 /* duration <= 0 ticks */
680 } else {
681 *ts = SYS_TICKS_TO_TIMESPEC(timeout.ticks);
682 }
683
684 __ASSERT_NO_MSG(timespec_is_valid(ts));
685}
686
716static inline k_timeout_t timespec_to_timeout(const struct timespec *req, struct timespec *rem)
717{
718 k_timeout_t timeout;
719
720 __ASSERT_NO_MSG((req != NULL) && timespec_is_valid(req));
721
722 if (timespec_compare(req, &SYS_TIMESPEC_NO_WAIT) <= 0) {
723 if (rem != NULL) {
724 *rem = *req;
725 }
726 /* equivalent of K_NO_WAIT without including kernel.h */
727 timeout.ticks = 0;
728 return timeout;
729 }
730
731 if (timespec_compare(req, &SYS_TIMESPEC_FOREVER) == 0) {
732 if (rem != NULL) {
734 }
735 /* equivalent of K_FOREVER without including kernel.h */
736 timeout.ticks = K_TICKS_FOREVER;
737 return timeout;
738 }
739
740 if (timespec_compare(req, &SYS_TIMESPEC_MAX) >= 0) {
741 /* round down to align to max ticks */
742 timeout.ticks = K_TICK_MAX;
743 } else {
744 /* round up to align to next tick boundary */
745 timeout.ticks = CLAMP(k_ns_to_ticks_ceil64(req->tv_nsec) +
747 K_TICK_MIN, K_TICK_MAX);
748 }
749
750 if (rem != NULL) {
751 timespec_from_timeout(timeout, rem);
752 timespec_sub(rem, req);
753 timespec_negate(rem);
754 }
755
756 return timeout;
757}
758
763#ifdef __cplusplus
764}
765#endif
766
767#endif /* ZEPHYR_INCLUDE_SYS_TIMEUTIL_H_ */
_TIME_T_ time_t
Definition _timespec.h:14
#define NSEC_PER_SEC
number of nanoseconds per second
Definition clock.h:113
#define K_TICKS_FOREVER
Definition clock.h:51
#define K_TIMEOUT_EQ(a, b)
Compare timeouts for equality.
Definition clock.h:80
#define IS_ENABLED(config_macro)
Check for macro definition in compiler-visible expressions.
Definition util_macro.h:148
#define CLAMP(val, low, high)
Clamp a value to a given range.
Definition util.h:418
#define DIV_ROUND_UP(n, d)
Divide and round up.
Definition util.h:353
time_t timeutil_timegm(const struct tm *tm)
Convert broken-down time to a POSIX epoch offset in seconds.
static k_timeout_t timespec_to_timeout(const struct timespec *req, struct timespec *rem)
Convert a timespec to a kernel timeout.
Definition timeutil.h:716
static void timespec_from_timeout(k_timeout_t timeout, struct timespec *ts)
Convert a kernel timeout to a timespec.
Definition timeutil.h:665
int64_t timeutil_timegm64(const struct tm *tm)
Convert broken-down time to a POSIX epoch offset in seconds.
int timeutil_sync_state_set_skew(struct timeutil_sync_state *tsp, float skew, const struct timeutil_sync_instant *base)
Update the state with a new skew and possibly base value.
int timeutil_sync_ref_from_local(const struct timeutil_sync_state *tsp, uint64_t local, uint64_t *refp)
Interpolate a reference timescale instant from a local instant.
int timeutil_sync_state_update(struct timeutil_sync_state *tsp, const struct timeutil_sync_instant *inst)
Record a new instant in the time synchronization state.
int32_t timeutil_sync_skew_to_ppb(float skew)
Convert from a skew to an error in parts-per-billion.
float timeutil_sync_estimate_skew(const struct timeutil_sync_state *tsp)
Estimate the skew based on current state.
int timeutil_sync_local_from_ref(const struct timeutil_sync_state *tsp, uint64_t ref, int64_t *localp)
Interpolate a local timescale instant from a reference instant.
static bool timespec_is_valid(const struct timespec *ts)
Check if a timespec is valid.
Definition timeutil.h:375
static bool timespec_negate(struct timespec *ts)
Negate a timespec object.
Definition timeutil.h:553
static bool timespec_normalize(struct timespec *ts)
Normalize a timespec so that the tv_nsec field is in valid range.
Definition timeutil.h:418
static bool timespec_add(struct timespec *a, const struct timespec *b)
Add one timespec to another.
Definition timeutil.h:510
static bool timespec_sub(struct timespec *a, const struct timespec *b)
Subtract one timespec from another.
Definition timeutil.h:592
static bool timespec_equal(const struct timespec *a, const struct timespec *b)
Check if two timespec objects are equal.
Definition timeutil.h:636
static int timespec_compare(const struct timespec *a, const struct timespec *b)
Compare two timespec objects.
Definition timeutil.h:614
#define k_ns_to_ticks_ceil64(t)
Convert nanoseconds to ticks.
Definition time_units.h:1115
#define k_sec_to_ticks_ceil64(t)
Convert seconds to ticks.
Definition time_units.h:539
#define NULL
Definition iar_missing_defs.h:20
#define LONG_MAX
Definition limits.h:41
#define LONG_MIN
Definition limits.h:46
__UINT32_TYPE__ uint32_t
Definition stdint.h:90
__INT32_TYPE__ int32_t
Definition stdint.h:74
__UINT64_TYPE__ uint64_t
Definition stdint.h:91
#define INT64_MIN
Definition stdint.h:25
__INT64_TYPE__ int64_t
Definition stdint.h:75
#define INT64_MAX
Definition stdint.h:19
Kernel timeout type.
Definition clock.h:65
k_ticks_t ticks
Definition clock.h:66
Definition _timespec.h:22
long tv_nsec
Definition _timespec.h:24
time_t tv_sec
Definition _timespec.h:23
Immutable state for synchronizing two clocks.
Definition timeutil.h:135
uint32_t ref_Hz
The nominal instance counter rate in Hz.
Definition timeutil.h:143
uint32_t local_Hz
The nominal local counter rate in Hz.
Definition timeutil.h:156
Representation of an instant in two time scales.
Definition timeutil.h:166
uint64_t ref
An instant in the reference time scale.
Definition timeutil.h:172
uint64_t local
The corresponding instance in the local time scale.
Definition timeutil.h:178
State required to convert instants between time scales.
Definition timeutil.h:191
const struct timeutil_sync_config * cfg
Pointer to reference and local rate information.
Definition timeutil.h:193
float skew
The scale factor used to correct for clock skew.
Definition timeutil.h:219
struct timeutil_sync_instant latest
The most recent instant in both time scales.
Definition timeutil.h:202
struct timeutil_sync_instant base
The base instant in both time scales.
Definition timeutil.h:196
Definition time.h:24
Misc utilities.
#define SYS_TIME_T_MAX
Definition timeutil.h:44
#define SYS_TIMESPEC_FOREVER
Definition timeutil.h:79
#define SYS_TIMESPEC_MAX
Definition timeutil.h:76
#define SYS_TIME_T_MIN
Definition timeutil.h:45
#define SYS_TICKS_TO_TIMESPEC(ticks)
Definition timeutil.h:66
#define SYS_TIMESPEC_NO_WAIT
Definition timeutil.h:70
Macros to abstract toolchain specific capabilities.