| // Copyright Microsoft and CHERIoT Contributors. |
| // SPDX-License-Identifier: MIT |
| |
| #pragma once |
| /** |
| * @file timeout.h |
| * |
| * This file contains the types used for timeouts across scheduler APIs. |
| */ |
| |
| #include <cdefs.h> |
| #include <stdint.h> |
| |
| /** |
| * Quantity used for measuring time for timeouts. The unit is scheduler ticks. |
| */ |
| typedef uint32_t Ticks; |
| |
| /// Value indicating an unbounded timeout. |
| static __if_cxx(constexpr) const Ticks UnlimitedTimeout = UINT32_MAX; |
| |
| /** |
| * Structure representing a timeout. This is intended to allow a single |
| * instance to be chained across blocking calls. |
| * |
| * Timeouts *may not be stored in the heap*. Handling timeout structures that |
| * may disappear between sleeping and waking is very complicated and would |
| * impact a lot of fast paths. Instead, most functions that take a timeout |
| * will simply fail if the timeout is on the heap. |
| */ |
| typedef struct Timeout |
| { |
| /** |
| * The time that has elapsed during blocking operations for this timeout |
| * structure. This should be initialised to 0. It may exceed the initial |
| * value of `remaining` if a higher-priority thread preempts the blocking |
| * thread. |
| */ |
| Ticks elapsed __if_cxx(= 0); |
| /** |
| * The remaining time. This is clamped at 0 on subtraction. A special |
| * value of `UnlimitedTimeout` can be set to represent an unlimited |
| * timeout. |
| */ |
| Ticks remaining; |
| #ifdef __cplusplus |
| /** |
| * Constructor, initialises this structure to allow `time` ticks to |
| * elapse. |
| */ |
| Timeout(Ticks time) : remaining(time) {} |
| |
| /** |
| * Constructor that initialises both fields, should be used only for |
| * initialiser-list initialisation in code that needs to compile as both C |
| * and C++. |
| */ |
| Timeout(Ticks elapsed, Ticks remaining) |
| : elapsed(elapsed), remaining(remaining) |
| { |
| } |
| |
| /** |
| * Update this timeout if `time` ticks have elapsed. This function |
| * saturates the values on overflow. |
| */ |
| inline void elapse(Ticks time) |
| { |
| if (__builtin_add_overflow(time, elapsed, &elapsed)) |
| { |
| elapsed = UnlimitedTimeout; |
| } |
| if (remaining != UnlimitedTimeout && |
| __builtin_sub_overflow(remaining, time, &remaining)) |
| { |
| remaining = 0; |
| } |
| } |
| |
| /** |
| * Helper indicating whether the owner of this timeout may block. |
| */ |
| bool may_block() |
| { |
| return remaining > 0; |
| } |
| #endif |
| } Timeout; |