The latest development version of this page may be more current than this released 3.7.0 version.

Network Timeout

Overview

Zephyr’s network infrastructure mostly uses the millisecond-resolution uptime clock to track timeouts, with both deadlines and durations measured with 32-bit unsigned values. The 32-bit value rolls over at 49 days 17 hours 2 minutes 47.296 seconds.

Timeout processing is often affected by latency, so that the time at which the timeout is checked may be some time after it should have expired. Handling this correctly without arbitrary expectations of maximum latency requires that the maximum delay that can be directly represented be a 31-bit non-negative number (INT32_MAX), which overflows at 24 days 20 hours 31 minutes 23.648 seconds.

Most network timeouts are shorter than the delay rollover, but a few protocols allow for delays that are represented as unsigned 32-bit values counting seconds, which corresponds to a 42-bit millisecond count.

The net_timeout API provides a generic timeout mechanism to correctly track the remaining time for these extended-duration timeouts.

Use

The simplest use of this API is:

  1. Configure a network timeout using net_timeout_set().

  2. Use net_timeout_evaluate() to determine how long it is until the timeout occurs. Schedule a timeout to occur after this delay.

  3. When the timeout callback is invoked, use net_timeout_evaluate() again to determine whether the timeout has completed, or whether there is additional time remaining. If the latter, reschedule the callback.

  4. While the timeout is running, use net_timeout_remaining() to get the number of seconds until the timeout expires. This may be used to explicitly update the timeout, which should be done by canceling any pending callback and restarting from step 1 with the new timeout.

The net_timeout contains a sys_snode_t that allows multiple timeout instances to be aggregated to share a single kernel timer element. The application must use net_timeout_evaluate() on all instances to determine the next timeout event to occur.

net_timeout_deadline() may be used to reconstruct the full-precision deadline of the timeout. This exists primarily for testing but may have use in some applications, as it does allow a millisecond-resolution calculation of remaining time.

API Reference

group net_timeout

Network long timeout primitives and helpers.

Defines

NET_TIMEOUT_MAX_VALUE

Divisor used to support ms resolution timeouts.

Because delays are processed in work queues which are not invoked synchronously with clock changes we need to be able to detect timeouts after they occur, which requires comparing “deadline” to “now” with enough “slop” to handle any observable latency due to “now” advancing past “deadline”.

The simplest solution is to use the native conversion of the well-defined 32-bit unsigned difference to a 32-bit signed difference, which caps the maximum delay at INT32_MAX. This is compatible with the standard mechanism for detecting completion of deadlines that do not overflow their representation.

Functions

void net_timeout_set(struct net_timeout *timeout, uint32_t lifetime, uint32_t now)

Configure a network timeout structure.

Parameters:
  • timeout – a pointer to the timeout state.

  • lifetime – the duration of the timeout in seconds.

  • now – the time at which the timeout started counting down, in milliseconds. This is generally a captured value of k_uptime_get_32().

int64_t net_timeout_deadline(const struct net_timeout *timeout, int64_t now)

Return the 64-bit system time at which the timeout will complete.

Note

Correct behavior requires invocation of net_timeout_evaluate() at its specified intervals.

Parameters:
Returns:

the value of k_uptime_get() at which the timeout will expire.

uint32_t net_timeout_remaining(const struct net_timeout *timeout, uint32_t now)

Calculate the remaining time to the timeout in whole seconds.

Note

This function rounds the remaining time down, i.e. if the timeout will occur in 3500 milliseconds the value 3 will be returned.

Note

Correct behavior requires invocation of net_timeout_evaluate() at its specified intervals.

Parameters:
  • timeout – a pointer to the timeout state

  • now – the time relative to which the estimate of remaining time should be calculated. This should be recently captured value from k_uptime_get_32().

Return values:
  • 0 – if the timeout has completed.

  • positive – the remaining duration of the timeout, in seconds.

uint32_t net_timeout_evaluate(struct net_timeout *timeout, uint32_t now)

Update state to reflect elapsed time and get new delay.

This function must be invoked periodically to (1) apply the effect of elapsed time on what remains of a total delay that exceeded the maximum representable delay, and (2) determine that either the timeout has completed or that the infrastructure must wait a certain period before checking again for completion.

Parameters:
  • timeout – a pointer to the timeout state

  • now – the time relative to which the estimate of remaining time should be calculated. This should be recently captured value from k_uptime_get_32().

Return values:
  • 0 – if the timeout has completed

  • positive – the maximum delay until the state of this timeout should be re-evaluated, in milliseconds.

struct net_timeout
#include <net_timeout.h>

Generic struct for handling network timeouts.

Except for the linking node, all access to state from these objects must go through the defined API.

Public Members

sys_snode_t node

Used to link multiple timeouts that share a common timer infrastructure.

For examples a set of related timers may use a single delayed work structure, which is always scheduled at the shortest time to a timeout event.

uint32_t timer_start

Time at which the timer was last set.

This usually corresponds to the low 32 bits of k_uptime_get().

uint32_t timer_timeout

Portion of remaining timeout that does not exceed NET_TIMEOUT_MAX_VALUE.

This value is updated in parallel with timer_start and wrap_counter by net_timeout_evaluate().

uint32_t wrap_counter

Timer wrap count.

This tracks multiples of NET_TIMEOUT_MAX_VALUE milliseconds that have yet to pass. It is also updated along with timer_start and wrap_counter by net_timeout_evaluate().