Skip to content

kernel: add k_clock api: remove posix dependency from iso c time #90096

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 17 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
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
1 change: 0 additions & 1 deletion MAINTAINERS.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2556,7 +2556,6 @@ Utilities:
- tests/unit/list/
- tests/unit/intmath/
- tests/unit/pot/
- tests/lib/time/
- tests/lib/onoff/
- tests/lib/sys_util/
- tests/lib/sprintf/
Expand Down
125 changes: 125 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 @@ -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:
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
87 changes: 87 additions & 0 deletions include/zephyr/kernel.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ BUILD_ASSERT(sizeof(intptr_t) == sizeof(long));
#define Z_DECL_POLL_EVENT
#endif

struct timespec;

struct k_thread;
struct k_mutex;
struct k_sem;
Expand Down Expand Up @@ -6486,6 +6488,91 @@ void k_sys_runtime_stats_enable(void);
*/
void k_sys_runtime_stats_disable(void);

/**
* @defgroup kernel_clock_apis Kernel Clock APIs
* @ingroup kernel_apis
* @{
*/

/**
* @brief The real-time clock (i.e. "wall clock")
*
* This clock is used to measure time since the epoch (1970-01-01 00:00:00 UTC).
*
* It is not a steady clock; i.e. it may be adjusted for a number of reasons from initialization
* of a hardware real-time-clock, to network-time synchronization, to manual adjustment from the
* application.
*/
#define K_CLOCK_REALTIME 1

/**
* @brief The monotonic clock
*
* This steady clock is used to measure time since the system booted. Time from this clock is
* always monotonically increasing.
*/
#define K_CLOCK_MONOTONIC 4

/**
* @brief The flag used for specifying absolute timeouts
*
* This flag may be passed to @ref k_clock_nanosleep to indicate the requested timeout is an
* absolute time with respect to the specified clock.
*/
#define K_TIMER_ABSTIME 4

/**
* @brief Get the current time from the specified clock
*
* @param clock_id The clock from which to query time.
* @param tp Pointer to memory where time will be written.
* @retval 0 on success.
* @retval -EINVAL when an invalid @a clock_id is specified.
*/
__syscall int k_clock_gettime(int clock_id, struct timespec *tp);

/**
* @brief Set the current time for the specified clock
*
* @param clock_id The clock for which the time should be set.
* @param tp Pointer to memory specifying the desired time.
* @retval 0 on success.
* @retval -EINVAL when an invalid @a clock_id is specified.
* @retval -EINVAL when @a tp contains nanoseconds outside of the range `[0, 999999999]`.
*/
__syscall int k_clock_settime(int clock_id, const struct timespec *tp);

/**
* @brief Sleep for the specified amount of time with respect to the specified clock.
*
* This function will cause the calling thread to sleep either
* - until the absolute time specified by @a rqtp (if @a flags includes @ref K_TIMER_ABSTIME), or
* - until the relative time specified by @a rqtp (if @a flags does not include
* @ref K_TIMER_ABSTIME).
*
* The accepted values for @a clock_id include
* - @ref K_CLOCK_REALTIME
* - @ref K_CLOCK_MONOTONIC
*
* If @a rmtp is not NULL, and the thread is awoken prior to the time specified by @a rqtp, then
* any remaining time will be written to @a rmtp. If the thread has slept for at least the time
* specified by @a rqtp, then @a rmtp will be set to zero.
*
* @param clock_id The clock to by which to sleep.
* @param flags Flags to modify the behavior of the sleep operation.
* @param rqtp Pointer to the requested time to sleep.
* @param rmtp Pointer to memory into which to copy the remaining time, if any.
*
* @retval 0 on success.
* @retval -EINVAL when an invalid @a clock_id, when @a rqtp contains nanoseconds outside of the
* range `[0, 999999999]`, or when @a rqtp contains a negative value.
*/
__syscall int k_clock_nanosleep(int clock_id, int flags, const struct timespec *rqtp,
struct timespec *rmtp);
/**
* @}
*/

#ifdef __cplusplus
}
#endif
Expand Down
4 changes: 2 additions & 2 deletions include/zephyr/posix/time.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ extern "C" {
#endif

#ifndef CLOCK_REALTIME
#define CLOCK_REALTIME 1
#define CLOCK_REALTIME K_CLOCK_REALTIME
#endif

#ifndef CLOCK_PROCESS_CPUTIME_ID
Expand All @@ -78,7 +78,7 @@ extern "C" {
#endif

#ifndef CLOCK_MONOTONIC
#define CLOCK_MONOTONIC 4
#define CLOCK_MONOTONIC K_CLOCK_MONOTONIC
#endif

#ifndef TIMER_ABSTIME
Expand Down
Loading
Loading