blob: 1b8184482b51fdea438ba64b9e615c2ef66447a5 [file] [log] [blame]
// 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;