diff --git a/doc/kernel/timeutil.rst b/doc/kernel/timeutil.rst index 203d52ea9af..f6312b49539 100644 --- a/doc/kernel/timeutil.rst +++ b/doc/kernel/timeutil.rst @@ -28,6 +28,7 @@ The time utilities API supports: * :ref:`converting between time representations ` * :ref:`synchronizing and aligning time scales ` +* :ref:`comparing, adding, and subtracting representations ` For terminology and concepts that support these functions see :ref:`timeutil_concepts`. @@ -65,6 +66,20 @@ The inverse transformation is not standardized: APIs like ``mktime()`` expect information about time zones. Zephyr provides this transformation with :c:func:`timeutil_timegm` and :c:func:`timeutil_timegm64`. +To convert between ``struct timespec`` and ``k_timeout_t`` durations, +use :c:func:`timespec_to_timeout` and :c:func:`timespec_from_timeout`. + +.. code-block:: c + + k_timeout_t to; + struct timespec ts; + + timespec_from_timeout(K_FOREVER, &ts); + to = timespec_to_timeout(&ts); /* to == K_FOREVER */ + + timespec_from_timeout(K_MSEC(100), &ts); + to = timespec_to_timeout(&ts); /* to == K_MSEC(100) */ + .. doxygengroup:: timeutil_repr_apis .. _timeutil_sync: @@ -106,6 +121,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 @@ -236,3 +335,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.