godspeed/task.rs
1// SPDX-License-Identifier: Apache-2.0
2//! This service's own execution: giving up the CPU, waiting, and what time it is.
3//!
4//! # Waiting is not the same as sleeping
5//!
6//! The functions here wait on the CLOCK, and that makes them the wrong tool for waiting on another
7//! service. Commandment VIII: wait on the truth, not on time. If you are sleeping because a peer
8//! might not be ready yet, you have written a race that passes on your machine - wait for the thing
9//! itself ([`crate::ipc::recv_within`], a reply, an interrupt), and let it tell you.
10//!
11//! What a sleep IS for: pacing something that has no event to wait on. A poll of an external device,
12//! a retry after congestion, a display that should not repaint faster than anyone can read.
13
14use godspeed_sdk::service_context::ServiceContext;
15
16pub use godspeed_sdk::service_context::{ClockSource, Datetime};
17/// The kernel's fixed authorities: (resource id, contract name, what it allows) - for naming a capability.
18pub use godspeed_sdk::service_context::AUTHORITIES;
19
20/// Give up the rest of this quantum.
21///
22/// Advisory only: the scheduler preempts at 10 ms regardless (CLAUDE.md 9.3), so this is politeness
23/// rather than a correctness tool. It cannot be relied on to let another service run, and a loop that
24/// needs it to make progress is a loop that should be blocking on something.
25pub fn yield_now(ctx: &ServiceContext) {
26 ctx.yield_cpu();
27}
28
29/// Sleep for `ms` milliseconds.
30///
31/// Read the module header before reaching for this: if something else could tell you when to wake,
32/// waiting for THAT is both faster and correct on a machine you have not tried yet.
33pub fn sleep_ms(ctx: &ServiceContext, ms: u64) {
34 ctx.sleep_ms(ms);
35}
36
37/// Sleep for one scheduler quantum, parked: the shortest sleep there is.
38///
39/// Not [`yield_now`]. A yield returns at once when nothing else is runnable, so a loop built on it
40/// spins a core; this parks the task for one quantum, 10 ms (CLAUDE.md 9.1). For a loop that has
41/// nothing to wait on but must not hammer the CPU between looks.
42pub fn sleep_quantum(ctx: &ServiceContext) {
43 // A quantum AS A DURATION, not one counter tick. One tick was right where the kernel floors a
44 // short sleep to the next scheduler tick, and wrong on a real Pi 2: its counter runs at 1 MHz, so
45 // one tick is 1 us, which the ARMv7 sub-tick sleep path (`handle_sleep`) takes, and this returned
46 // after about a microsecond (`backlog/fixed/80` G4). On a clock the kernel could not calibrate,
47 // `sleep_ms` falls back to that one tick - the floor, which is still one quantum there.
48 ctx.sleep_ms(10);
49}
50
51/// Sleep for `us` microseconds, at the kernel's resolution.
52///
53/// The kernel's sleep ends on a scheduler tick on every port but ARMv7 (the Pi 2), which has a
54/// sub-tick timer for sleeps under a quantum and falls back to the tick when its few slots are taken;
55/// elsewhere anything under a quantum becomes a quantum. This is for a pace written in microseconds,
56/// not a hardware hold - a hold that must not be cut short or
57/// stretched belongs to `gs::driver::delay`. On a machine whose clock the kernel could not calibrate
58/// it is one quantum, the same floor [`sleep_ms`] has there.
59pub fn sleep_us(ctx: &ServiceContext, us: u64) {
60 let per_10ms = ctx.tsc_ticks_per_10ms();
61 ctx.sleep(if per_10ms == 0 { 1 } else { crate::driver::wait::ticks_for(per_10ms, us) });
62}
63
64/// Sleep for `ticks` of the counter [`crate::driver::wait::ticks`] reads.
65///
66/// For code that already works in counter ticks - a driver that measured how long the kernel's sleep
67/// really lasts on this board and schedules against that measurement. Anything written in time uses
68/// [`sleep_ms`] or [`sleep_us`], which convert for you and know what an uncalibrated machine means;
69/// a hand-converted tick count here is the copy those exist to replace. Zero is treated as one: a
70/// sleep of nothing is a yield, and [`yield_now`] says so.
71pub fn sleep_ticks(ctx: &ServiceContext, ticks: u64) {
72 ctx.sleep(ticks.max(1));
73}
74
75/// Seconds since this machine booted.
76///
77/// Monotonic and always available, including before any clock is set, which is what makes it the
78/// right basis for "how long has this taken" - unlike the wall clock, which can be unset or can jump
79/// when the wall clock is learned.
80pub fn uptime_secs(ctx: &ServiceContext) -> i64 {
81 ctx.uptime_secs()
82}
83
84/// Seconds that never go backwards (InspectKernel query 17).
85///
86/// For stamping a sequence of events where ordering matters more than absolute accuracy. **The
87/// origin depends on the board**: on x86 it is the CMOS RTC's epoch seconds with backward and
88/// wild-forward readings dropped; on the boards with no RTC (the Pis, the VisionFive) it is seconds
89/// since boot. Use it for differences, never as a date.
90pub fn epoch_secs_monotonic(ctx: &ServiceContext) -> i64 {
91 ctx.epoch_secs_monotonic()
92}
93
94/// The HARDWARE real-time clock as calendar fields (InspectKernel query 11), with
95/// [`Datetime::epoch_secs`] to turn it into epoch seconds.
96///
97/// **This is the RTC, not the `time` service's clock.** The wall clock left the kernel for the
98/// `time` service, which corrects it from the network or carries a floor across boots; none of
99/// that reaches this call. So [`clock_source`] can answer [`ClockSource::Ntp`] or
100/// [`ClockSource::Floor`] while this still reads the raw hardware.
101///
102/// **A machine may not have one.** On the boards with no RTC (the Pis, the VisionFive) the kernel
103/// answers 0, which unpacks to all-zero fields - year 0, not today and not 1970 - and stays that
104/// way after the network has supplied the time. On x86 it is the CMOS clock, unchecked. Check
105/// [`clock_source`] rather than printing this; [`uptime_secs`] is the one that is always
106/// meaningful.
107pub fn datetime(ctx: &ServiceContext) -> Datetime {
108 ctx.datetime()
109}
110
111/// Where the wall clock came from, so a displayed timestamp can say what it stands on.
112///
113/// This is the check [`datetime`] tells you to make, and it is the difference between a date and a
114/// date you can quote. The four answers are genuinely different claims:
115///
116/// | | |
117/// |---|---|
118/// | [`ClockSource::Unset`] | No clock at all. Whatever [`datetime`] renders is not today. |
119/// | [`ClockSource::Rtc`] | A local hardware clock reading a plausible date. |
120/// | [`ClockSource::Ntp`] | Corrected from the network this boot. |
121/// | [`ClockSource::Floor`] | A LOWER BOUND carried from the last boot - real, advancing correctly, but blind to how long the machine was off. |
122///
123/// `Floor` is the one worth reading twice, and it is why this is an enum rather than a bool. Several
124/// of the boards this runs on have no RTC, so the clock starts from a persisted floor and creeps
125/// forward correctly while being arbitrarily far behind. Reporting that as `Rtc` would claim hardware
126/// the board does not have; reporting it as `Unset` would deny a time it is displaying.
127///
128/// **A machine that cannot be asked reads [`ClockSource::Unset`]**, deliberately. The `time` service
129/// is restartable, so an unanswered question is normal during a restart - and an unknown clock and an
130/// unset clock oblige a caller to do the same thing, which is not to quote the date as fact.
131pub fn clock_source(ctx: &ServiceContext) -> ClockSource {
132 wall_clock(ctx).map(|(_, source)| source).unwrap_or(ClockSource::Unset)
133}
134
135/// The `time` service's clock: epoch seconds, and where they came from ([`clock_source`] explains the
136/// four answers). `None` when there is no clock or `time` did not answer, which oblige a caller to the
137/// same thing: not to treat any number as the date.
138///
139/// For a program that must CHECK a date - a certificate's validity, a signature's freshness - rather
140/// than show one. A `Floor` reading is a lower bound: a date it calls "not yet valid" may be real, and
141/// a caller says which clock it used.
142pub fn wall_clock(ctx: &ServiceContext) -> Option<(i64, ClockSource)> {
143 // OP_NOW -> [ok, epoch(8), source]. Bounded, and reacquiring: see `crate::call::request_within`.
144 const OP_NOW: u8 = 1;
145 let reply = crate::call::request_within(ctx, "time", &godspeed_sdk::ipc::Message::from_bytes(&[OP_NOW]), 2).ok()?;
146 let p = reply.payload_bytes();
147 if p.len() < 10 || p[0] == 0 {
148 return None;
149 }
150 let epoch = i64::from_le_bytes([p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8]]);
151 let source = match p[9] {
152 1 => ClockSource::Rtc,
153 2 => ClockSource::Ntp,
154 3 => ClockSource::Floor,
155 _ => return None,
156 };
157 Some((epoch, source))
158}
159
160/// A random 32-bit word from the hardware (InspectKernel query 19), or `None` on a machine whose port
161/// exposes no hardware random source. Ungated: entropy confers no authority.
162///
163/// **There is deliberately no fallback.** A program that needs secrets - a TLS key share - must refuse
164/// to run without this rather than reach for a timer or a counter, which would make a key an attacker
165/// can predict while everything appears to work.
166pub fn hw_random(ctx: &ServiceContext) -> Option<u32> {
167 ctx.hw_random()
168}
169
170/// Whether the `time` service's clock is worth showing as a date at all.
171///
172/// Says nothing about [`datetime`] on a board with no RTC: there `Ntp` can be true while
173/// [`datetime`] still reads zeros (see its doc).
174///
175/// True for [`ClockSource::Rtc`] and [`ClockSource::Ntp`]. False for [`ClockSource::Unset`], and
176/// false for [`ClockSource::Floor`] - a floor is a real lower bound but not a reading, so a program
177/// that only wants to know "may I print this as today's date" should treat it as no.
178///
179/// Reach for [`clock_source`] when the distinction matters, which it does more often than this
180/// shorthand suggests.
181pub fn clock_is_set(ctx: &ServiceContext) -> bool {
182 matches!(clock_source(ctx), ClockSource::Rtc | ClockSource::Ntp)
183}
184
185/// Which core this service is running on.
186///
187/// For reporting, not for deciding. Placement is the supervisor's (CLAUDE.md 9.2), a service never
188/// migrates while it runs, and it may be placed on a different core after a restart - so a service
189/// that CHANGES BEHAVIOUR based on this has coupled itself to a deployment detail that is explicitly
190/// allowed to move (invariant 11).
191pub fn core_id(ctx: &ServiceContext) -> u32 {
192 ctx.core_id()
193}