Zephyr API Documentation 4.1.99
A Scalable Open Source RTOS
 4.1.99
All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
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
51/* Base Year value use in calculations in "timeutil_timegm64" API */
52#define TIME_UTILS_BASE_YEAR 1900
53
64
76time_t timeutil_timegm(const struct tm *tm);
77
120
142
183
202 const struct timeutil_sync_instant *inst);
203
229 const struct timeutil_sync_instant *base);
230
245
269 uint64_t local, uint64_t *refp);
270
293 uint64_t ref, int64_t *localp);
294
314
337static inline bool timespec_is_valid(const struct timespec *ts)
338{
339 __ASSERT_NO_MSG(ts != NULL);
340
341 return (ts->tv_nsec >= 0) && (ts->tv_nsec < NSEC_PER_SEC);
342}
343
380static inline bool timespec_normalize(struct timespec *ts)
381{
382 __ASSERT_NO_MSG(ts != NULL);
383
384#if defined(CONFIG_SPEED_OPTIMIZATIONS) && HAS_BUILTIN(__builtin_add_overflow)
385
386 int sign = (ts->tv_nsec >= 0) - (ts->tv_nsec < 0);
387 int64_t sec = (ts->tv_nsec >= (long)NSEC_PER_SEC) * (ts->tv_nsec / (long)NSEC_PER_SEC) +
388 ((ts->tv_nsec < 0) && (ts->tv_nsec != LONG_MIN)) *
389 DIV_ROUND_UP((unsigned long)-ts->tv_nsec, (long)NSEC_PER_SEC) +
390 (ts->tv_nsec == LONG_MIN) * ((LONG_MAX / NSEC_PER_SEC) + 1);
391 bool overflow = __builtin_add_overflow(ts->tv_sec, sign * sec, &ts->tv_sec);
392
393 ts->tv_nsec -= sign * (long)NSEC_PER_SEC * sec;
394
395 if (!overflow) {
396 __ASSERT_NO_MSG(timespec_is_valid(ts));
397 }
398
399 return !overflow;
400
401#else
402
403 long sec;
404
405 if (ts->tv_nsec >= (long)NSEC_PER_SEC) {
406 sec = ts->tv_nsec / (long)NSEC_PER_SEC;
407 } else if (ts->tv_nsec < 0) {
408 if ((sizeof(ts->tv_nsec) == sizeof(uint32_t)) && (ts->tv_nsec == LONG_MIN)) {
410 } else {
411 sec = DIV_ROUND_UP((unsigned long)-ts->tv_nsec, NSEC_PER_SEC);
412 }
413 } else {
414 sec = 0;
415 }
416
417 if ((ts->tv_nsec < 0) && (ts->tv_sec < 0) && (ts->tv_sec - INT64_MIN < sec)) {
418 /*
419 * When `tv_nsec` is negative and `tv_sec` is already most negative,
420 * further subtraction would cause integer overflow.
421 */
422 return false;
423 }
424
425 if ((ts->tv_nsec >= (long)NSEC_PER_SEC) && (ts->tv_sec > 0) &&
426 (INT64_MAX - ts->tv_sec < sec)) {
427 /*
428 * When `tv_nsec` is >= `NSEC_PER_SEC` and `tv_sec` is already most
429 * positive, further addition would cause integer overflow.
430 */
431 return false;
432 }
433
434 if (ts->tv_nsec >= (long)NSEC_PER_SEC) {
435 ts->tv_sec += sec;
436 ts->tv_nsec -= sec * (long)NSEC_PER_SEC;
437 } else if (ts->tv_nsec < 0) {
438 ts->tv_sec -= sec;
439 ts->tv_nsec += sec * (long)NSEC_PER_SEC;
440 } else {
441 /* no change: SonarQube was complaining */
442 }
443
444 __ASSERT_NO_MSG(timespec_is_valid(ts));
445
446 return true;
447
448#endif
449}
450
466static inline bool timespec_add(struct timespec *a, const struct timespec *b)
467{
468 __ASSERT_NO_MSG((a != NULL) && timespec_is_valid(a));
469 __ASSERT_NO_MSG((b != NULL) && timespec_is_valid(b));
470
471#if defined(CONFIG_SPEED_OPTIMIZATIONS) && HAS_BUILTIN(__builtin_add_overflow)
472
473 return !__builtin_add_overflow(a->tv_sec, b->tv_sec, &a->tv_sec) &&
474 !__builtin_add_overflow(a->tv_nsec, b->tv_nsec, &a->tv_nsec) &&
476
477#else
478
479 if ((a->tv_sec < 0) && (b->tv_sec < 0) && (INT64_MIN - a->tv_sec > b->tv_sec)) {
480 /* negative integer overflow would occur */
481 return false;
482 }
483
484 if ((a->tv_sec > 0) && (b->tv_sec > 0) && (INT64_MAX - a->tv_sec < b->tv_sec)) {
485 /* positive integer overflow would occur */
486 return false;
487 }
488
489 a->tv_sec += b->tv_sec;
490 a->tv_nsec += b->tv_nsec;
491
492 return timespec_normalize(a);
493
494#endif
495}
496
509static inline bool timespec_negate(struct timespec *ts)
510{
511 __ASSERT_NO_MSG((ts != NULL) && timespec_is_valid(ts));
512
513#if defined(CONFIG_SPEED_OPTIMIZATIONS) && HAS_BUILTIN(__builtin_sub_overflow)
514
515 return !__builtin_sub_overflow(0LL, ts->tv_sec, &ts->tv_sec) &&
516 !__builtin_sub_overflow(0L, ts->tv_nsec, &ts->tv_nsec) && timespec_normalize(ts);
517
518#else
519
520 /* note: must check for 32-bit size here until #90029 is resolved */
521 if (((sizeof(ts->tv_sec) == sizeof(int32_t)) && (ts->tv_sec == INT32_MIN)) ||
522 ((sizeof(ts->tv_sec) == sizeof(int64_t)) && (ts->tv_sec == INT64_MIN))) {
523 /* -INT64_MIN > INT64_MAX, so +ve integer overflow would occur */
524 return false;
525 }
526
527 ts->tv_sec = -ts->tv_sec;
528 ts->tv_nsec = -ts->tv_nsec;
529
530 return timespec_normalize(ts);
531
532#endif
533}
534
550static inline bool timespec_sub(struct timespec *a, const struct timespec *b)
551{
552 __ASSERT_NO_MSG(a != NULL);
553 __ASSERT_NO_MSG(b != NULL);
554
555 struct timespec neg = *b;
556
557 return timespec_negate(&neg) && timespec_add(a, &neg);
558}
559
572static inline int timespec_compare(const struct timespec *a, const struct timespec *b)
573{
574 __ASSERT_NO_MSG((a != NULL) && timespec_is_valid(a));
575 __ASSERT_NO_MSG((b != NULL) && timespec_is_valid(b));
576
577 return (((a->tv_sec == b->tv_sec) && (a->tv_nsec < b->tv_nsec)) * -1) +
578 (((a->tv_sec == b->tv_sec) && (a->tv_nsec > b->tv_nsec)) * 1) +
579 ((a->tv_sec < b->tv_sec) * -1) + ((a->tv_sec > b->tv_sec));
580}
581
594static inline bool timespec_equal(const struct timespec *a, const struct timespec *b)
595{
596 __ASSERT_NO_MSG(a != NULL);
597 __ASSERT_NO_MSG(b != NULL);
598
599 return (a->tv_sec == b->tv_sec) && (a->tv_nsec == b->tv_nsec);
600}
601
620static inline void timespec_from_timeout(k_timeout_t timeout, struct timespec *ts)
621{
622 __ASSERT_NO_MSG(ts != NULL);
623
624#if defined(CONFIG_SPEED_OPTIMIZATIONS)
625
626 uint64_t ns = k_ticks_to_ns_ceil64(timeout.ticks);
627
628 *ts = (struct timespec){
629 .tv_sec = (timeout.ticks == K_TICKS_FOREVER) * INT64_MAX +
630 (timeout.ticks != K_TICKS_FOREVER) * (ns / NSEC_PER_SEC),
631 .tv_nsec = (timeout.ticks == K_TICKS_FOREVER) * (NSEC_PER_SEC - 1) +
632 (timeout.ticks != K_TICKS_FOREVER) * (ns % NSEC_PER_SEC),
633 };
634
635#else
636
637 if (timeout.ticks == 0) {
638 /* This is equivalent to K_NO_WAIT, but without including <zephyr/kernel.h> */
639 ts->tv_sec = 0;
640 ts->tv_nsec = 0;
641 } else if (timeout.ticks == K_TICKS_FOREVER) {
642 /* This is roughly equivalent to K_FOREVER, but not including <zephyr/kernel.h> */
643 ts->tv_sec = (time_t)INT64_MAX;
644 ts->tv_nsec = NSEC_PER_SEC - 1;
645 } else {
646 uint64_t ns = k_ticks_to_ns_ceil64(timeout.ticks);
647
648 ts->tv_sec = ns / NSEC_PER_SEC;
649 ts->tv_nsec = ns - ts->tv_sec * NSEC_PER_SEC;
650 }
651
652#endif
653
654 __ASSERT_NO_MSG(timespec_is_valid(ts));
655}
656
674static inline k_timeout_t timespec_to_timeout(const struct timespec *ts)
675{
676 __ASSERT_NO_MSG((ts != NULL) && timespec_is_valid(ts));
677
678#if defined(CONFIG_SPEED_OPTIMIZATIONS)
679
680 return (k_timeout_t){
681 /* note: must check for 32-bit size here until #90029 is resolved */
682 .ticks = ((sizeof(ts->tv_sec) == sizeof(int32_t) && (ts->tv_sec == INT32_MAX) &&
683 (ts->tv_nsec == NSEC_PER_SEC - 1)) ||
684 ((sizeof(ts->tv_sec) == sizeof(int64_t)) && (ts->tv_sec == INT64_MAX) &&
685 (ts->tv_nsec == NSEC_PER_SEC - 1))) *
687 ((sizeof(ts->tv_sec) == sizeof(int32_t) && (ts->tv_sec == INT32_MAX) &&
688 (ts->tv_nsec == NSEC_PER_SEC - 1)) ||
689 ((sizeof(ts->tv_sec) == sizeof(int64_t)) && (ts->tv_sec != INT64_MAX) &&
690 (ts->tv_sec >= 0))) *
691 (IS_ENABLED(CONFIG_TIMEOUT_64BIT)
692 ? (int64_t)(CLAMP(
695 0, (uint64_t)INT64_MAX))
696 : (uint32_t)(CLAMP(
699 0, (uint64_t)UINT32_MAX)))};
700
701#else
702
703 if ((ts->tv_sec < 0) || (ts->tv_sec == 0 && ts->tv_nsec == 0)) {
704 /* This is equivalent to K_NO_WAIT, but without including <zephyr/kernel.h> */
705 return (k_timeout_t){
706 .ticks = 0,
707 };
708 /* note: must check for 32-bit size here until #90029 is resolved */
709 } else if (((sizeof(ts->tv_sec) == sizeof(int32_t)) && (ts->tv_sec == INT32_MAX) &&
710 (ts->tv_nsec == NSEC_PER_SEC - 1)) ||
711 ((sizeof(ts->tv_sec) == sizeof(int64_t)) && (ts->tv_sec == INT64_MAX) &&
712 (ts->tv_nsec == NSEC_PER_SEC - 1))) {
713 /* This is equivalent to K_FOREVER, but not including <zephyr/kernel.h> */
714 return (k_timeout_t){
715 .ticks = K_TICKS_FOREVER,
716 };
717 } else {
718 if (IS_ENABLED(CONFIG_TIMEOUT_64BIT)) {
719 return (k_timeout_t){
722 0, (uint64_t)INT64_MAX),
723 };
724 } else {
725 return (k_timeout_t){
728 0, (uint64_t)UINT32_MAX),
729 };
730 }
731 }
732
733#endif
734}
735
740#ifdef __cplusplus
741}
742#endif
743
744#endif /* ZEPHYR_INCLUDE_SYS_TIMEUTIL_H_ */
_TIME_T_ time_t
Definition _timespec.h:14
#define NSEC_PER_SEC
number of nanoseconds per second
Definition sys_clock.h:113
#define NSEC_PER_USEC
number of nanoseconds per microsecond
Definition sys_clock.h:83
#define K_TICKS_FOREVER
Definition sys_clock.h:51
#define USEC_PER_SEC
number of microseconds per second
Definition sys_clock.h:110
#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 void timespec_from_timeout(k_timeout_t timeout, struct timespec *ts)
Convert a kernel timeout to a timespec.
Definition timeutil.h:620
static k_timeout_t timespec_to_timeout(const struct timespec *ts)
Convert a timespec to a kernel timeout.
Definition timeutil.h:674
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:337
static bool timespec_negate(struct timespec *ts)
Negate a timespec object.
Definition timeutil.h:509
static bool timespec_normalize(struct timespec *ts)
Normalize a timespec so that the tv_nsec field is in valid range.
Definition timeutil.h:380
static bool timespec_add(struct timespec *a, const struct timespec *b)
Add one timespec to another.
Definition timeutil.h:466
static bool timespec_sub(struct timespec *a, const struct timespec *b)
Subtract one timespec from another.
Definition timeutil.h:550
static bool timespec_equal(const struct timespec *a, const struct timespec *b)
Check if two timespec objects are equal.
Definition timeutil.h:594
static int timespec_compare(const struct timespec *a, const struct timespec *b)
Compare two timespec objects.
Definition timeutil.h:572
#define k_ticks_to_ns_ceil64(t)
Convert ticks to nanoseconds.
Definition time_units.h:1979
#define k_ns_to_ticks_floor64(t)
Convert nanoseconds to ticks.
Definition time_units.h:1051
#define k_sec_to_ticks_floor64(t)
Convert seconds to ticks.
Definition time_units.h:475
#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
#define INT32_MAX
Definition stdint.h:18
__UINT64_TYPE__ uint64_t
Definition stdint.h:91
#define INT32_MIN
Definition stdint.h:24
#define INT64_MIN
Definition stdint.h:25
#define UINT32_MAX
Definition stdint.h:29
__INT64_TYPE__ int64_t
Definition stdint.h:75
#define INT64_MAX
Definition stdint.h:19
Kernel timeout type.
Definition sys_clock.h:65
k_ticks_t ticks
Definition sys_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:97
uint32_t ref_Hz
The nominal instance counter rate in Hz.
Definition timeutil.h:105
uint32_t local_Hz
The nominal local counter rate in Hz.
Definition timeutil.h:118
Representation of an instant in two time scales.
Definition timeutil.h:128
uint64_t ref
An instant in the reference time scale.
Definition timeutil.h:134
uint64_t local
The corresponding instance in the local time scale.
Definition timeutil.h:140
State required to convert instants between time scales.
Definition timeutil.h:153
const struct timeutil_sync_config * cfg
Pointer to reference and local rate information.
Definition timeutil.h:155
float skew
The scale factor used to correct for clock skew.
Definition timeutil.h:181
struct timeutil_sync_instant latest
The most recent instant in both time scales.
Definition timeutil.h:164
struct timeutil_sync_instant base
The base instant in both time scales.
Definition timeutil.h:158
Definition time.h:24
Misc utilities.
Variables needed for system clock.
Macros to abstract toolchain specific capabilities.