Skip to content

sys: timeutil: add utility functions for struct timespec #90060

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 111 additions & 0 deletions doc/kernel/timeutil.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ The time utilities API supports:

* :ref:`converting between time representations <timeutil_repr>`
* :ref:`synchronizing and aligning time scales <timeutil_sync>`
* :ref:`comparing, adding, and subtracting representations <timeutil_manip>`

For terminology and concepts that support these functions see
:ref:`timeutil_concepts`.
Expand Down Expand Up @@ -106,6 +107,90 @@ process:

.. doxygengroup:: timeutil_sync_apis

.. _timeutil_manip:

``timespec`` Manipulation
=========================

Checking the validity of a ``timespec`` can be done with :c:func:`timespec_is_valid`.

.. code-block:: c

struct timespec ts = {
.tv_sec = 0,
.tv_nsec = -1, /* out of range! */
};

if (!timespec_is_valid(&ts)) {
/* error-handing code */
}

In some cases, invalid ``timespec`` objects may be re-normalized using
:c:func:`timespec_normalize`.

.. code-block:: c

if (!timespec_normalize(&ts)) {
/* error-handling code */
}

/* ts should be normalized */
__ASSERT(timespec_is_valid(&ts) == true, "expected normalized timespec");

It is possible to compare two ``timespec`` objects for equality using :c:func:`timespec_equal`.

.. code-block:: c

if (timespec_equal(then, now)) {
/* time is up! */
}

It is possible to compare and fully order (valid) ``timespec`` objects using
:c:func:`timespec_compare`.

.. code-block:: c

int cmp = timespec_compare(a, b);

switch (cmp) {
case 0:
/* a == b */
break;
case -1:
/* a < b */
break;
case +1:
/* a > b */
break;
}

It is possible to add, subtract, and negate ``timespec`` objects using
:c:func:`timespec_add`, :c:func:`timespec_sub`, and :c:func:`timespec_negate`,
respectively. Like :c:func:`timespec_normalize`, these functions will output
a normalized ``timespec`` when doing so would not result in overflow.
On success, these functions return ``true``. If overflow would occur, the
functions return ``false``.

.. code-block:: c

/* a += b */
if (!timespec_add(&a, &b)) {
/* overflow */
}

/* a -= b */
if (!timespec_sub(&a, &b)) {
/* overflow */
}

/* a = -a */
if (!timespec_negate(&a)) {
/* overflow */
}

.. doxygengroup:: timeutil_timespec_apis


.. _timeutil_concepts:

Concepts Underlying Time Support in Zephyr
Expand Down Expand Up @@ -236,3 +321,29 @@ The mechanism used to populate synchronization points is not relevant: it may
involve reading from a local high-precision RTC peripheral, exchanging packets
over a network using a protocol like NTP or PTP, or processing NMEA messages
received a GPS with or without a 1pps signal.

``timespec`` Concepts
=====================

Originally from POSIX, ``struct timespec`` has been a part of the C standard
since C11. The definition of ``struct timespec`` is as shown below.

.. code-block:: c

struct timespec {
time_t tv_sec; /* seconds */
long tv_nsec; /* nanoseconds */
};

.. _note:

The C standard does not define the size of ``time_t``. However, Zephyr
uses 64-bits for ``time_t``. The ``long`` type is required to be at least
32-bits, but usually matches the word size of the architecture. Both
elements of ``struct timespec`` are signed integers. ``time_t`` is defined
to be 64-bits both for historical reasons and to be robust enough to
represent times in the future.

The ``tv_nsec`` field is only valid with values in the range ``[0, 999999999]``. The
``tv_sec`` field is the number of seconds since the epoch. If ``struct timespec`` is
used to express a difference, the ``tv_sec`` field may fall into a negative range.
Loading
Loading