Skip to main content

detcore/syscalls/
time.rs

1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree.
7 */
8
9//! System calls for dealing with threads and concurrency.
10use std::time::Duration;
11
12use nix::sys::signal::Signal;
13use reverie::Error;
14use reverie::Guest;
15use reverie::Stack;
16use reverie::syscalls;
17use reverie::syscalls::AddrMut;
18use reverie::syscalls::ClockId;
19use reverie::syscalls::Errno;
20use reverie::syscalls::MemoryAccess;
21use reverie::syscalls::Syscall;
22use reverie::syscalls::Sysno;
23use reverie::syscalls::Timespec;
24use reverie::syscalls::Timeval;
25use reverie::syscalls::family::NanosleepFamily;
26use tracing::error;
27use tracing::info;
28use tracing::trace;
29
30use super::signal::SleepCheck;
31use super::signal::SleepSignal;
32use crate::cpu_clock;
33use crate::cpu_clock::ClockIdClass;
34use crate::cpu_clock::ClockLookup;
35use crate::cpu_clock::ClockTask;
36use crate::detlog;
37use crate::record_or_replay::RecordOrReplay;
38use crate::resources::Permission;
39use crate::resources::ResourceID;
40use crate::resources::Resources;
41use crate::scheduler::Priority;
42use crate::scheduler::entropy_to_priority;
43use crate::tool_global::PosixTimerNotification;
44use crate::tool_global::ResumeStatus;
45use crate::tool_global::SigalrmControl;
46use crate::tool_global::posix_timer_thread;
47use crate::tool_global::refuse_sigalrm;
48use crate::tool_global::register_posix_timer;
49use crate::tool_global::thread_observe_time;
50use crate::tool_local::Detcore;
51use crate::types::LogicalTime;
52use crate::types::PosixTimerThread;
53use crate::types::SigWrapper;
54
55/// Whether Linux accepts `clockid` in clock_gettime and clock_getres, as far as
56/// the id alone decides: the fixed clocks 0 to 9 and CLOCK_TAI (11). Linux
57/// answers EINVAL for 10 (CLOCK_SGI_CYCLE, gone since Linux 4.x) and for
58/// every id from 12 up. A negative id names a process's or thread's CPU
59/// clock, or a clock descriptor; whether it is valid depends on the process
60/// or descriptor it names, so it is accepted here as before.
61fn clock_id_is_known(clockid: ClockId) -> bool {
62    match raw_clock_id(clockid) {
63        0..=9 | 11 => true,
64        id => id < 0,
65    }
66}
67
68/// `clockid` as the kernel's `clockid_t`.
69fn raw_clock_id(clockid: ClockId) -> i32 {
70    use reverie::syscalls::FromToRaw;
71    clockid.into_raw() as i32
72}
73
74/// Linux's answer to `timer_create` for `clockid` alone, which it gives
75/// before it reads the notification (`do_timer_create`,
76/// kernel/time/posix-timers.c:448-455 at v6.12): EINVAL for an id with no
77/// clock (`clockid_to_kclock` and the `posix_clocks` table at :1529-1556: 10,
78/// and 12 up), EOPNOTSUPP for a clock with no timers (CLOCK_MONOTONIC_RAW,
79/// CLOCK_REALTIME_COARSE, CLOCK_MONOTONIC_COARSE, and a clock descriptor: a
80/// negative id with `(id & CLOCKFD_MASK) == CLOCKFD`, which names
81/// `clock_posix_dynamic`, kernel/time/posix-clock.c:334-339, whatever
82/// descriptor it encodes; include/linux/posix-timers_types.h:24-32), and
83/// EINVAL for a negative id whose clock bits name no CPU clock (`(id & 7) ==
84/// 7`: per-thread with CPUCLOCK_WHICH 3, which is CPUCLOCK_MAX, so
85/// `pid_for_clock` refuses it from the bits alone,
86/// kernel/time/posix-cpu-timers.c:63-64, and `posix_cpu_timer_create`
87/// answers EINVAL, :392-395). `None` for the clocks with timers, for the
88/// alarm clocks (whose answer depends on the host) and for the other
89/// negative ids, CPU clocks, whose answer depends on the process or thread
90/// the id names: a CPU-clock id naming a task that does not exist therefore
91/// gets the reserved-signal EPERM where Linux answers EINVAL. Only a
92/// `timer_create` whose sigevent names a reserved signal reads it, right
93/// after the copy and before the notification is checked, as Linux orders
94/// them, so that neither the refusal nor Detcore's notification checks come
95/// before Linux's clock answer. Detcore's virtual timers do not otherwise
96/// check the clock, which https://github.com/rrnewton/hermit/issues/4556
97/// tracks together with the CPU-clock case above.
98fn timer_create_clock_refusal(clockid: ClockId) -> Option<Errno> {
99    use reverie::syscalls::FromToRaw;
100    const CLOCKFD: i32 = 3;
101    const CLOCKFD_MASK: i32 = 4 | 3;
102    if !clock_id_is_known(clockid) {
103        return Some(Errno::EINVAL);
104    }
105    match clockid.into_raw() as i32 {
106        libc::CLOCK_MONOTONIC_RAW | libc::CLOCK_REALTIME_COARSE | libc::CLOCK_MONOTONIC_COARSE => {
107            Some(Errno::EOPNOTSUPP)
108        }
109        id if id < 0 && id & CLOCKFD_MASK == CLOCKFD => Some(Errno::EOPNOTSUPP),
110        // CPUCLOCK_PERTHREAD_MASK | CPUCLOCK_MAX: no CPU clock.
111        id if id < 0 && id & CLOCKFD_MASK == CLOCKFD_MASK => Some(Errno::EINVAL),
112        _ => None,
113    }
114}
115
116fn time_from_resources(rsrcs: &Resources) -> Option<LogicalTime> {
117    if rsrcs.resources.len() > 1 {
118        panic!(
119            "time_from_resources: multiple resource ids in resource request: {:?}",
120            rsrcs
121        );
122    }
123    for rs in rsrcs.resources.iter() {
124        if let (ResourceID::SleepUntil(tm), _) = rs {
125            return Some(*tm);
126        }
127    }
128    None
129}
130
131/// Flatten a `timespec` to nanoseconds. Negative fields are not valid for the
132/// timer syscalls we handle; treat them as zero rather than panicking.
133fn timespec_to_ns(ts: libc::timespec) -> u64 {
134    let secs = ts.tv_sec.max(0) as u64;
135    let nsec = ts.tv_nsec.max(0) as u64;
136    secs.saturating_mul(1_000_000_000).saturating_add(nsec)
137}
138
139/// The CPU time an absolute CPU-clock sleep to `deadline` still has to wait
140/// for when the clock reads `now`: none once the deadline has passed, where
141/// Linux returns at once (`posix_cpu_timer_set` fires an expired timer,
142/// kernel/time/posix-cpu-timers.c:729-735 at v6.16). The caller checked the
143/// request's fields; the deadline saturates.
144fn cpu_sleep_remaining(deadline: &Timespec, now: LogicalTime) -> Duration {
145    let deadline =
146        LogicalTime::ZERO + Duration::new(deadline.tv_sec as u64, deadline.tv_nsec as u32);
147    if deadline > now {
148        deadline.duration_since(now)
149    } else {
150        Duration::ZERO
151    }
152}
153
154/// Inverse of [`timespec_to_ns`].
155fn ns_to_timespec(ns: u64) -> libc::timespec {
156    libc::timespec {
157        tv_sec: (ns / 1_000_000_000) as libc::time_t,
158        tv_nsec: (ns % 1_000_000_000) as libc::c_long,
159    }
160}
161
162// AUTONOMOUS-BOT-IMPLEMENTED
163// TODO-HUMAN-REVIEW(PR-857): Query-only timex mode boundary.
164fn timex_mode_is_query(modes: libc::c_uint) -> bool {
165    modes == 0 || modes == libc::ADJ_OFFSET_SS_READ
166}
167
168// AUTONOMOUS-BOT-IMPLEMENTED
169// TODO-HUMAN-REVIEW(PR-857): Host-independent NTP discipline snapshot.
170fn deterministic_timex(now: Timespec) -> libc::timex {
171    // SAFETY: `libc::timex` contains only integer fields and padding; zero is a
172    // valid baseline for the fields not modeled by Hermit.
173    let mut tx: libc::timex = unsafe { std::mem::zeroed() };
174    tx.status = libc::STA_UNSYNC;
175    tx.tick = 10_000;
176    tx.time = libc::timeval {
177        tv_sec: now.tv_sec,
178        tv_usec: now.tv_nsec / 1_000,
179    };
180    tx
181}
182
183// AUTONOMOUS-BOT-IMPLEMENTED
184// TODO-HUMAN-REVIEW(PR-845): Review SaBRe thread-local guest clock reads.
185pub(crate) async fn guest_clock_time<G, T>(guest: &mut G) -> LogicalTime
186where
187    G: Guest<Detcore<T>>,
188    T: RecordOrReplay,
189{
190    let raw = thread_observe_time(guest).await;
191    guest.thread_state().observe_guest_clock(raw)
192}
193
194/// Replacing host time in the `tv` of a `gettimeofday` that failed with EFAULT
195/// could not finish. `tv` may still hold host wall-clock time, so this is a
196/// failed run, not a guest errno.
197#[derive(Debug, Clone, Copy, PartialEq, Eq)]
198struct TvRepairFailure {
199    /// The word being stored: `tv_sec` or `tv_usec`.
200    field: &'static str,
201    kind: TvRepairFailureKind,
202}
203
204#[derive(Debug, Clone, Copy, PartialEq, Eq)]
205#[cfg_attr(
206    not(target_arch = "x86_64"),
207    allow(
208        dead_code,
209        reason = "the repair's time(2) probes, which build most of these, are x86_64-only"
210    )
211)]
212enum TvRepairFailureKind {
213    /// The backend could not execute the `time(2)` probe. EFAULT is not a
214    /// failure: it means Linux stopped before storing this word.
215    ProbeFailed(Errno),
216    /// After a store probe returned EFAULT, `time(NULL)`, which Linux cannot
217    /// fail, failed too. Something other than the store, such as a seccomp
218    /// filter, produced the EFAULT, so it says nothing about `tv`.
219    ControlProbeFailed(Errno),
220    /// A word at or after the one whose store probe returned EFAULT no longer
221    /// reads as it did before the call, so the original call stored it and the
222    /// EFAULT did not come from the store.
223    StoppedWordChanged,
224    /// A word at or after the one whose store probe returned EFAULT could not
225    /// be read before or after the call, although every byte of it is mapped.
226    /// The read failure may not be a fault: a seccomp filter can deny the
227    /// read while the store went through, so nothing shows the word unstored.
228    StoppedWordUnreadable,
229    /// The guest's memory map, needed to tell an unmapped word from an
230    /// unreadable one, could not be read or was empty.
231    MapsUnavailable,
232    /// The exact overwrite after a successful probe failed. The probe just
233    /// stored host seconds, so the run cannot safely continue.
234    OverwriteFailed(Errno),
235    /// The one-shot overwrite reported a count other than the whole word.
236    OverwriteCount { expected: usize, reported: usize },
237    /// Adding the field offset to the guest's `timeval` address overflowed.
238    AddressOverflow,
239    /// A recorded EFAULT does not prove that this replay execution performed
240    /// the original stores, so live probing would mix replayed and host state.
241    ReplayMode,
242    /// This architecture has no `time(2)` to probe each word with.
243    #[cfg(not(target_arch = "x86_64"))]
244    NoStoreProbe,
245}
246
247impl std::fmt::Display for TvRepairFailure {
248    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
249        write!(
250            f,
251            "replacing host time in the {} of a failed gettimeofday: ",
252            self.field
253        )?;
254        match self.kind {
255            TvRepairFailureKind::ProbeFailed(errno) => {
256                write!(f, "time(2) store probe failed: {errno}")
257            }
258            TvRepairFailureKind::ControlProbeFailed(errno) => write!(
259                f,
260                "time(NULL) control probe failed: {errno}, so the store probe's EFAULT was not a store fault"
261            ),
262            TvRepairFailureKind::StoppedWordChanged => f.write_str(
263                "the word changed during the call although its store probe returned EFAULT",
264            ),
265            TvRepairFailureKind::StoppedWordUnreadable => f.write_str(
266                "the word is mapped but could not be read, so its store probe's EFAULT is unconfirmed",
267            ),
268            TvRepairFailureKind::MapsUnavailable => {
269                f.write_str("the guest's memory map could not be read")
270            }
271            TvRepairFailureKind::OverwriteFailed(errno) => {
272                write!(f, "virtual-time overwrite failed: {errno}")
273            }
274            TvRepairFailureKind::OverwriteCount { expected, reported } => write!(
275                f,
276                "virtual-time overwrite reported {reported} of {expected} bytes"
277            ),
278            TvRepairFailureKind::AddressOverflow => f.write_str("field address overflowed"),
279            TvRepairFailureKind::ReplayMode => {
280                f.write_str("cannot probe a recorded or replayed EFAULT")
281            }
282            #[cfg(not(target_arch = "x86_64"))]
283            TvRepairFailureKind::NoStoreProbe => f.write_str(
284                "this architecture has no time(2) to probe which words Linux stored",
285            ),
286        }
287    }
288}
289
290impl std::error::Error for TvRepairFailure {}
291
292fn tv_repair_error(field: &'static str, kind: TvRepairFailureKind) -> Error {
293    Error::Tool(anyhow::Error::new(TvRepairFailure { field, kind }))
294}
295
296#[cfg(target_arch = "x86_64")]
297#[derive(Debug, Clone, Copy, PartialEq, Eq)]
298enum TimeStoreProbe {
299    Stored,
300    Stopped,
301}
302
303#[cfg(target_arch = "x86_64")]
304fn classify_time_store_probe(
305    field: &'static str,
306    result: Result<i64, Errno>,
307) -> Result<TimeStoreProbe, Error> {
308    match result {
309        Ok(_) => Ok(TimeStoreProbe::Stored),
310        Err(Errno::EFAULT) => Ok(TimeStoreProbe::Stopped),
311        Err(errno) => Err(tv_repair_error(
312            field,
313            TvRepairFailureKind::ProbeFailed(errno),
314        )),
315    }
316}
317
318/// `time(NULL)` stores nothing and cannot fail on Linux, so any error means
319/// the injected `time(2)` never reached the native call.
320#[cfg(target_arch = "x86_64")]
321fn require_native_time_control_probe(
322    field: &'static str,
323    result: Result<i64, Errno>,
324) -> Result<(), Error> {
325    match result {
326        Ok(_) => Ok(()),
327        Err(errno) => Err(tv_repair_error(
328            field,
329            TvRepairFailureKind::ControlProbeFailed(errno),
330        )),
331    }
332}
333
334/// How a word that Linux did not store reads after the call.
335#[cfg(target_arch = "x86_64")]
336#[derive(Debug, Clone, Copy, PartialEq, Eq)]
337enum StoppedWord {
338    /// Readable, with the value it held before the call.
339    Unchanged,
340    /// Unreadable both before and after the call. This proves nothing by
341    /// itself; see [`require_unmapped_unreadable_word`].
342    Unreadable,
343}
344
345/// A word Linux did not store keeps both its contents and its readability.
346#[cfg(target_arch = "x86_64")]
347fn require_unchanged_stopped_word(
348    field: &'static str,
349    before: Result<libc::time_t, Errno>,
350    after: Result<libc::time_t, Errno>,
351) -> Result<StoppedWord, Error> {
352    match (before, after) {
353        (Ok(before), Ok(after)) if before == after => Ok(StoppedWord::Unchanged),
354        (Err(_), Err(_)) => Ok(StoppedWord::Unreadable),
355        _ => Err(tv_repair_error(
356            field,
357            TvRepairFailureKind::StoppedWordChanged,
358        )),
359    }
360}
361
362/// Whether every byte of the `time_t` at `word` lies in one of `ranges`, the
363/// half-open address ranges of the guest's mappings.
364#[cfg(target_arch = "x86_64")]
365fn time_word_is_fully_mapped(mut ranges: Vec<(u64, u64)>, word: u64) -> bool {
366    let Some(end) = word.checked_add(std::mem::size_of::<libc::time_t>() as u64) else {
367        return false;
368    };
369    ranges.sort_unstable();
370    let mut covered = word;
371    for (start, stop) in ranges {
372        if start <= covered && covered < stop {
373            covered = stop;
374            if covered >= end {
375                return true;
376            }
377        }
378    }
379    false
380}
381
382/// An unreadable word is accepted as unstored only when part of it is
383/// unmapped: Linux's eight-byte `put_user` faults there before storing any
384/// byte. A failed read of a fully mapped word is not evidence of a fault: a
385/// seccomp filter can deny the read while the store succeeds. Ptrace reads use
386/// `FOLL_FORCE`, which bypasses page permissions, but some listed mappings
387/// still refuse the read: file pages beyond end of file, hardware-poisoned
388/// pages, `MADV_GUARD_INSTALL` guard regions, `VM_PFNMAP` mappings without an
389/// `access` operation, missing pages of a userfaultfd region in SIGBUS mode,
390/// and `[vsyscall]` in xonly mode. Backends
391/// that read with `process_vm_readv` also cannot read `PROT_NONE` pages. A
392/// `gettimeofday` whose store faults on any of these ends the run rather than
393/// returning EFAULT. An empty map is refused because a filter that fakes a
394/// successful zero-byte read would otherwise make every word look unmapped.
395#[cfg(target_arch = "x86_64")]
396fn require_unmapped_unreadable_word(
397    field: &'static str,
398    maps: Result<Vec<(u64, u64)>, Error>,
399    word: u64,
400) -> Result<(), Error> {
401    let ranges = match maps {
402        Ok(ranges) if !ranges.is_empty() => ranges,
403        Ok(_) => {
404            error!("gettimeofday tv repair: the guest's memory map is empty");
405            return Err(tv_repair_error(field, TvRepairFailureKind::MapsUnavailable));
406        }
407        Err(err) => {
408            error!("gettimeofday tv repair: reading the guest's memory map: {err}");
409            return Err(tv_repair_error(field, TvRepairFailureKind::MapsUnavailable));
410        }
411    };
412    if time_word_is_fully_mapped(ranges, word) {
413        Err(tv_repair_error(
414            field,
415            TvRepairFailureKind::StoppedWordUnreadable,
416        ))
417    } else {
418        Ok(())
419    }
420}
421
422/// What Detcore's memory reader returned for `tv_sec` and `tv_usec` before a
423/// `gettimeofday`, with the read error where it failed. Under ptrace the read
424/// ignores page protection and protection keys; backends that read with
425/// `process_vm_readv` respect `VM_READ`.
426type TimevalWordSnapshot = [Result<libc::time_t, Errno>; 2];
427
428const TIMEVAL_WORDS: [(&str, usize); 2] = [
429    ("tv_sec", std::mem::offset_of!(Timeval, tv_sec)),
430    ("tv_usec", std::mem::offset_of!(Timeval, tv_usec)),
431];
432
433fn snapshot_timeval_words<'a, G, T>(
434    guest: &mut G,
435    tv_addr: AddrMut<'a, Timeval>,
436) -> TimevalWordSnapshot
437where
438    G: Guest<Detcore<T>>,
439    T: RecordOrReplay,
440{
441    TIMEVAL_WORDS.map(|(field, offset)| {
442        let addr = timeval_word_addr(field, tv_addr, offset).map_err(|_| Errno::EFAULT)?;
443        guest.memory().read_value(addr)
444    })
445}
446
447fn timeval_word_addr<'a>(
448    field: &'static str,
449    tv_addr: AddrMut<'a, Timeval>,
450    offset: usize,
451) -> Result<AddrMut<'a, libc::time_t>, Error> {
452    tv_addr
453        .as_raw()
454        .checked_add(offset)
455        .and_then(AddrMut::<libc::time_t>::from_raw)
456        .ok_or_else(|| tv_repair_error(field, TvRepairFailureKind::AddressOverflow))
457}
458
459/// The address of `tv`'s word at `offset` for checking that a stopped
460/// `gettimeofday` left it alone, or `None` when the address is past the end of
461/// the address space. No store can reach such a word, so it needs no check.
462/// (A probe needs a real address, so `timeval_word_addr` fails closed instead.)
463#[cfg(target_arch = "x86_64")]
464fn stopped_timeval_word_addr<'a>(
465    tv_addr: AddrMut<'a, Timeval>,
466    offset: usize,
467) -> Option<AddrMut<'a, libc::time_t>> {
468    tv_addr
469        .as_raw()
470        .checked_add(offset)
471        .and_then(AddrMut::<libc::time_t>::from_raw)
472}
473
474#[cfg(target_arch = "x86_64")]
475fn require_complete_time_word_overwrite(
476    field: &'static str,
477    expected: usize,
478    result: Result<usize, Errno>,
479) -> Result<(), Error> {
480    match result {
481        Ok(reported) if reported == expected => Ok(()),
482        Ok(reported) => Err(tv_repair_error(
483            field,
484            TvRepairFailureKind::OverwriteCount { expected, reported },
485        )),
486        Err(errno) => Err(tv_repair_error(
487            field,
488            TvRepairFailureKind::OverwriteFailed(errno),
489        )),
490    }
491}
492
493fn require_live_time_store_probe(replay_data_is_some: bool) -> Result<(), Error> {
494    if replay_data_is_some {
495        Err(tv_repair_error("tv", TvRepairFailureKind::ReplayMode))
496    } else {
497        Ok(())
498    }
499}
500
501/// Replaces the host wall-clock time that a `gettimeofday` failing with EFAULT
502/// may have stored in `tv` with virtual time, in exactly the words Linux
503/// stored.
504///
505/// Linux stores `tv_sec`, then `tv_usec`, each with one eight-byte `put_user`,
506/// and only then copies `tz`; the first fault ends the call with EFAULT. A
507/// store that faults on either page it touches commits nothing, so each word
508/// is stored whole or not at all, and nothing after an unstored word is
509/// attempted. `time(2)` uses the same eight-byte `put_user` store for its
510/// `tloc`, so the repair injects it at each word in kernel order. EFAULT means
511/// the original call stopped at that word too. Success means the probe itself
512/// just stored host seconds in those exact bytes; only then does Hermit replace
513/// the word with its virtual value. Other probe errors and overwrite failures
514/// fail closed because host time may remain.
515///
516/// An EFAULT from the probe is only evidence about `tv` if it came from the
517/// store. A seccomp filter can return EFAULT for `time(2)` without running it,
518/// and would otherwise end the repair while host time remains in a writable
519/// `tv`. Two checks therefore confirm every EFAULT before it is trusted.
520/// First, `time(NULL)` is injected: it stores nothing and cannot fail on
521/// Linux, so any error means the probes are not reaching the native call.
522/// Second, every word from the stopped one onward must still read exactly as
523/// it did before the original call: readable with the same value, or
524/// unreadable both times and not fully mapped, so that the store could only
525/// have faulted. A changed word was stored by that call, and an unreadable
526/// word that is fully mapped may have been, because a failed read is not
527/// itself a fault. Each of these failures ends the run, including for the
528/// mapped but unreadable pages listed at `require_unmapped_unreadable_word`.
529///
530/// These checks are observations Detcore makes with its own syscalls, so they
531/// trust those syscalls' results, as every Detcore handler that reads back a
532/// result does. They catch a filter that makes a syscall fail, whether it is
533/// the guest's probe or Detcore's own read. A seccomp filter installed on
534/// Hermit itself can also make one of Detcore's own syscalls report success
535/// without running it, and that is outside this guarantee. A guest cannot
536/// install a filter: Detcore refuses `seccomp(2)` and `PR_SET_SECCOMP`.
537///
538/// The repair never writes a word the kernel could not store, and it does not
539/// test writability by rewriting a word, because a remote write ignores
540/// protection keys that deny the guest's own stores. The pre-call snapshot is
541/// a read only. The host seconds written by a successful
542/// probe exist transiently until the overwrite. Default thread
543/// sequentialization prevents another guest thread from observing that
544/// interval, but another process sharing the page can observe it; such
545/// external shared state is outside Hermit's determinism guarantee.
546/// Standard record/replay disables time virtualization, so this handler is not
547/// used there. A custom configuration that combines replay data with virtual
548/// time fails closed before probing: a recorded EFAULT does not establish that
549/// this execution performed any stores for a live `time(2)` to reproduce.
550///
551/// Every backend runs this repair. The memory map comes from
552/// `Guest::storable_memory_ranges`, which lists `/proc/<pid>/maps` of the
553/// guest by default and the guest's own page record on a backend whose
554/// `pid()` is not the guest (KVM). A backend that executes `gettimeofday` and
555/// `time(2)` itself, as KVM does, stores them as Linux does: each word with an
556/// all-or-nothing store to a writable page, in kernel order.
557#[cfg(target_arch = "x86_64")]
558async fn overwrite_failed_gettimeofday_tv<'a, G, T>(
559    guest: &mut G,
560    tv_addr: AddrMut<'a, Timeval>,
561    tv: &Timeval,
562    before: &TimevalWordSnapshot,
563) -> Result<(), Error>
564where
565    G: Guest<Detcore<T>>,
566    T: RecordOrReplay,
567{
568    let values = [tv.tv_sec as libc::time_t, tv.tv_usec as libc::time_t];
569    for (index, (field, offset)) in TIMEVAL_WORDS.into_iter().enumerate() {
570        let addr = timeval_word_addr(field, tv_addr, offset)?;
571        let probe = syscalls::Time::new().with_tloc(Some(addr));
572        match classify_time_store_probe(field, guest.inject(probe).await)? {
573            TimeStoreProbe::Stored => {
574                let bytes = values[index].to_ne_bytes();
575                let overwrite = guest
576                    .memory()
577                    .write_with_user_access(addr.cast::<u8>(), &bytes);
578                require_complete_time_word_overwrite(field, bytes.len(), overwrite)?;
579            }
580            TimeStoreProbe::Stopped => {
581                let control = syscalls::Time::new().with_tloc(None);
582                require_native_time_control_probe(field, guest.inject(control).await)?;
583                for (stopped, (field, offset)) in TIMEVAL_WORDS.into_iter().enumerate().skip(index)
584                {
585                    let Some(addr) = stopped_timeval_word_addr(tv_addr, offset) else {
586                        continue;
587                    };
588                    let after = guest.memory().read_value(addr);
589                    match require_unchanged_stopped_word(field, before[stopped], after)? {
590                        StoppedWord::Unchanged => {}
591                        StoppedWord::Unreadable => {
592                            let maps = guest.storable_memory_ranges();
593                            require_unmapped_unreadable_word(field, maps, addr.as_raw() as u64)?;
594                        }
595                    }
596                }
597                break;
598            }
599        }
600    }
601    Ok(())
602}
603
604/// The repair above probes each `tv` word with `time(2)`, which aarch64 does
605/// not have, so there it cannot tell which words Linux stored and refuses.
606#[cfg(not(target_arch = "x86_64"))]
607async fn overwrite_failed_gettimeofday_tv<'a, G, T>(
608    _guest: &mut G,
609    _tv_addr: AddrMut<'a, Timeval>,
610    _tv: &Timeval,
611    _before: &TimevalWordSnapshot,
612) -> Result<(), Error>
613where
614    G: Guest<Detcore<T>>,
615    T: RecordOrReplay,
616{
617    Err(tv_repair_error("tv", TvRepairFailureKind::NoStoreProbe))
618}
619
620fn remaining_sleep_duration(target: LogicalTime, now: LogicalTime) -> Duration {
621    if target > now {
622        target.duration_since(now)
623    } else {
624        Duration::ZERO
625    }
626}
627
628impl<T: RecordOrReplay> Detcore<T> {
629    /// Convenience function for constructing a sleep request with a nanosecond offset from "now".
630    /// A zero offset marks the request a zero-length sleep (`Resources::zero_length_sleep`).
631    pub async fn sleep_request<G: Guest<Self>>(guest: &mut G, ns_delta: Duration) -> Resources {
632        let base_time = thread_observe_time(guest).await;
633        let target_time = base_time + ns_delta;
634        let resource = ResourceID::SleepUntil(target_time);
635        let mut request = guest.thread_state().mk_request(resource, Permission::W);
636        request.zero_length_sleep = ns_delta.is_zero();
637        request
638    }
639
640    /// Convenience function for constructing a sleep request with a absolute nanosecond value from the realtime clock.
641    pub async fn sleep_request_abs<G: Guest<Self>>(guest: &mut G, time: LogicalTime) -> Resources {
642        // TODO T124594597 Record-replay case requires better handling of time
643        let resource = ResourceID::SleepUntil(time);
644        guest.thread_state().mk_request(resource, Permission::W)
645    }
646
647    /// Convenience function for constructing a thread yield request.
648    /// Implemented as a sleep ending at the epoch (in the past).
649    pub fn yield_request<G: Guest<Self>>(guest: &mut G) -> Resources {
650        let resource = ResourceID::SleepUntil(LogicalTime::from_nanos(0));
651        guest.thread_state().mk_request(resource, Permission::W)
652    }
653
654    /// Construct a request for a strong, one-turn scheduler yield.
655    pub fn sched_yield_request<G: Guest<Self>>(guest: &mut G) -> Resources {
656        guest
657            .thread_state()
658            .mk_request(ResourceID::SchedYield, Permission::W)
659    }
660
661    /// Construct a random PriorityChangePoint request using the local PRNG.
662    pub fn random_priority_changepoint_request<G: Guest<Self>>(
663        guest: &mut G,
664        change_time: LogicalTime,
665    ) -> Resources {
666        let entropy = guest.thread_state_mut().chaos_prng_next_u64("priority");
667        let new_priority = entropy_to_priority(entropy);
668        Self::priority_changepoint_request(guest, change_time, new_priority)
669    }
670
671    /// Construct a PriorityChangePoint request using the supplied time and priority.
672    pub fn priority_changepoint_request<G: Guest<Self>>(
673        guest: &mut G,
674        change_time: LogicalTime,
675        new_priority: Priority,
676    ) -> Resources {
677        // AUTONOMOUS-BOT-IMPLEMENTED
678        // TODO-HUMAN-REVIEW(PR-1151)
679        let epochs = guest.thread_state_mut().take_pending_chaos_epochs();
680        let rcbs = guest.thread_state().committed_clock_value;
681        let resource = ResourceID::PriorityChangePoint(new_priority, change_time, rcbs, epochs);
682        guest.thread_state().mk_request(resource, Permission::W)
683    }
684
685    /// gettimeofday
686    pub async fn handle_gettimeofday<G: Guest<Self>>(
687        &self,
688        guest: &mut G,
689        call: syscalls::Gettimeofday,
690    ) -> Result<i64, Error> {
691        let time_ns = guest_clock_time(guest).await;
692
693        // What Detcore could read in `tv` before the call; the repair uses it
694        // to confirm which words a failing call left alone.
695        let before = call.tv().map(|tp| snapshot_timeval_words(guest, tp.into()));
696
697        // A call failing with EFAULT may still have stored host wall-clock time
698        // in `tv`, so keep its result until `tv` holds virtual time.
699        let result = self
700            .record_or_replay_preserving_tool_errors(guest, call)
701            .await;
702
703        let tv: Timeval = time_ns.into();
704
705        if let Some(tp) = call.tv() {
706            match (&result, &before) {
707                (Ok(_), _) => guest.memory().write_value(tp, &tv)?,
708                // Linux's gettimeofday fails only with EFAULT, which is taken
709                // to be its own even when a seccomp filter returned it without
710                // running the call. Any other error came from the backend, the
711                // tool, a seccomp filter or a replayed log, and says nothing
712                // about what reached `tv`, so memory is left alone.
713                (Err(Error::Errno(Errno::EFAULT)), Some(before)) => {
714                    require_live_time_store_probe(self.cfg.replay_data.is_some())?;
715                    overwrite_failed_gettimeofday_tv(guest, tp.into(), &tv, before).await?
716                }
717                (Err(_), _) => {}
718            }
719        }
720
721        result
722    }
723
724    /// time
725    #[cfg(target_arch = "x86_64")]
726    pub async fn handle_time<G: Guest<Self>>(
727        &self,
728        guest: &mut G,
729        call: syscalls::Time,
730    ) -> Result<i64, Error> {
731        let time_ns = guest_clock_time(guest).await;
732        let secs = time_ns.as_secs() as i64;
733
734        if let Some(tloc) = call.tloc() {
735            let mut memory = guest.memory();
736            memory.write_value(tloc, &secs)?;
737        }
738
739        Ok(secs)
740    }
741
742    /// clock_gettime. A CPU clock reads Detcore's logical CPU accounting
743    /// (`crate::cpu_clock`); every other clock reads the guest clock. Every
744    /// accepted id first makes the guest-clock observation, a global request,
745    /// as every clock read always has, so a CPU-clock read keeps its place in
746    /// the schedule and only the value it returns is the CPU clock's.
747    pub async fn handle_clock_gettime<G: Guest<Self>>(
748        &self,
749        guest: &mut G,
750        call: syscalls::ClockGettime,
751    ) -> Result<i64, Error> {
752        if !clock_id_is_known(call.clockid()) {
753            return Err(Errno::EINVAL.into());
754        }
755        let guest_time = guest_clock_time(guest).await;
756        let time_ns = match cpu_clock::classify(raw_clock_id(call.clockid())) {
757            ClockIdClass::Other => guest_time,
758            ClockIdClass::NoCpuClock => return Err(Errno::EINVAL.into()),
759            ClockIdClass::Cpu(clock) => {
760                self.read_cpu_clock(guest, Sysno::clock_gettime, clock)
761                    .await?
762            }
763        };
764        trace!("Converting nanoseconds into clock_gettime: {}", time_ns);
765
766        let tp = call.tp().ok_or(Errno::EFAULT)?;
767
768        let t: Timespec = time_ns.into();
769
770        guest.memory().write_value(tp, &t)?;
771
772        Ok(0)
773    }
774
775    /// clock_getres
776    pub async fn handle_clock_getres<G: Guest<Self>>(
777        &self,
778        guest: &mut G,
779        call: syscalls::ClockGetres,
780    ) -> Result<i64, Error> {
781        if !clock_id_is_known(call.clockid()) {
782            return Err(Errno::EINVAL.into());
783        }
784        // A CPU clock is valid while the thread or process it names lives
785        // (`posix_cpu_clock_getres`, kernel/time/posix-cpu-timers.c:159-176 at
786        // v6.16), which is how glibc's `clock_getcpuclockid` checks a pid.
787        match cpu_clock::classify(raw_clock_id(call.clockid())) {
788            ClockIdClass::Other => {}
789            ClockIdClass::NoCpuClock => return Err(Errno::EINVAL.into()),
790            ClockIdClass::Cpu(clock) => {
791                self.cpu_clock_task(guest, Sysno::clock_getres, clock.owner, ClockLookup::Other)
792                    .await?;
793            }
794        }
795        // A NULL `res` pointer is valid for clock_getres: the kernel validates
796        // the clockid and returns 0 without storing the resolution. GHC's RTS
797        // probes the per-thread CPU clock exactly this way
798        // (clock_getres(clockid, NULL)) in getCurrentThreadCPUTime, so
799        // returning EFAULT here spuriously aborts the guest. Only write the
800        // resolution when the caller supplied a destination.
801        if let Some(res) = call.res() {
802            // For now we report a constant clock res of 10ms:
803            let clock_res = 10;
804
805            let t = Timespec {
806                tv_sec: 0,
807                tv_nsec: 1000 * clock_res as i64,
808            };
809
810            guest.memory().write_value(res, &t)?;
811        }
812
813        Ok(0)
814    }
815
816    // AUTONOMOUS-BOT-IMPLEMENTED
817    // TODO-HUMAN-REVIEW(PR-857): Deterministic adjtimex query/refusal policy.
818    /// Report Hermit's virtual clock with a fixed unsynchronized discipline.
819    /// Adjustment modes are capability-gated host mutations and receive EPERM.
820    pub async fn handle_adjtimex<G: Guest<Self>>(
821        &self,
822        guest: &mut G,
823        call: syscalls::Adjtimex,
824    ) -> Result<i64, Error> {
825        self.write_deterministic_timex(guest, call.buf()).await
826    }
827
828    // AUTONOMOUS-BOT-IMPLEMENTED
829    // TODO-HUMAN-REVIEW(PR-857): Deterministic clock_adjtime query/refusal policy.
830    /// Apply the adjtimex policy to CLOCK_REALTIME. Linux does not permit NTP
831    /// adjustment of the other fixed clock IDs, so reject them with EOPNOTSUPP.
832    pub async fn handle_clock_adjtime<G: Guest<Self>>(
833        &self,
834        guest: &mut G,
835        call: syscalls::ClockAdjtime,
836    ) -> Result<i64, Error> {
837        if call.clockid() != ClockId::CLOCK_REALTIME {
838            return Err(Errno::EOPNOTSUPP.into());
839        }
840        self.write_deterministic_timex(guest, call.buf()).await
841    }
842
843    async fn write_deterministic_timex<G: Guest<Self>>(
844        &self,
845        guest: &mut G,
846        buf: Option<reverie::syscalls::AddrMut<'_, libc::timex>>,
847    ) -> Result<i64, Error> {
848        let buf = buf.ok_or(Errno::EFAULT)?;
849        let request: libc::timex = guest.memory().read_value(buf)?;
850        if !timex_mode_is_query(request.modes) {
851            return Err(Errno::EPERM.into());
852        }
853
854        let now: Timespec = thread_observe_time(guest).await.into();
855        guest.memory().write_value(buf, &deterministic_timex(now))?;
856        Ok(libc::TIME_ERROR as i64)
857    }
858
859    /// Helper function to wait a given period, which may either succeed or be interrupted by a signal.
860    /// Return 0 or EINTR respectively.
861    async fn wait_and_return<R: Guest<Self>>(
862        &self,
863        guest: &mut R,
864        mut request: Resources,
865        call: NanosleepFamily,
866    ) -> Result<i64, Error> {
867        let target_time = time_from_resources(&request).expect("a sleepuntil resource request");
868        // Lets the scheduler end the sleep for a cross-task signal that
869        // interrupts it (`scheduler::sleep_signal`).
870        request.fyi(crate::resources::NANOSLEEP_FYI);
871        let mut claimed = false;
872        loop {
873            // A signal already pending ends the sleep before it parks, and one
874            // still pending after a wake ends it; a wake whose signal was taken
875            // back parks it again with its original absolute deadline
876            // (`super::signal::sleep_signal`).
877            if super::signal::sleep_signal(guest, SleepCheck::BeforePark, false).await?
878                == SleepSignal::Pending
879            {
880                break;
881            }
882            request.in_guest_sleep_sigalrm = self.in_guest_sleep_sigalrm_snapshot(guest).await;
883            match crate::tool_global::parked_wait_request(
884                guest,
885                request.clone(),
886                crate::scheduler::parked::ParkedWaitPolicy::NanosleepNoHandlerRestart {
887                    absolute_deadline: target_time,
888                },
889            )
890            .await
891            {
892                ResumeStatus::InGuestFatalAlarm => {
893                    // The default action terminates the guest. In particular,
894                    // do not observe time or write `rem` after this fatal wake.
895                    self.stage_in_guest_fatal_alarm(guest).await;
896                    return Err(Errno::EINTR.into());
897                }
898                // A sleep never asks for `NothingElseCanRun`.
899                ResumeStatus::Normal | ResumeStatus::NothingElseCanRun => return Ok(0),
900                ResumeStatus::Signaled(signals) => {
901                    match super::signal::sleep_signal(guest, SleepCheck::AfterWake(signals), false)
902                        .await?
903                    {
904                        SleepSignal::Pending | SleepSignal::Held => break,
905                        SleepSignal::Claimed => {
906                            claimed = true;
907                            break;
908                        }
909                        SleepSignal::None => trace!(
910                            "nanosleep woken for a signal no longer pending for it; sleeping again until {}",
911                            target_time
912                        ),
913                    }
914                }
915            }
916        }
917        let now = thread_observe_time(guest).await;
918        let delta = remaining_sleep_duration(target_time, now);
919        // Linux never touches remain for TIMER_ABSTIME, even when
920        // a caught signal interrupts the absolute sleep.
921        let addr2 = if call.flags() & libc::TIMER_ABSTIME == 0 {
922            call.rem()
923        } else {
924            None
925        };
926        if let Some(addr2) = addr2 {
927            info!(
928                "[interrupted] sleep till (until {}), woke up {:?} early, writing into nanosleep rem argument.",
929                target_time, delta
930            );
931            let t = Timespec {
932                tv_sec: delta.as_secs() as i64,
933                tv_nsec: delta.subsec_nanos() as i64,
934            };
935            guest.memory().write_value(addr2, &t)?;
936        } else {
937            info!("[interrupted] nanosleep rem argument is null, not writing it.")
938        }
939        if claimed {
940            // A claimed `SIGCHLD` is held for delivery as the thread resumes
941            // (`SleepSignal::Claimed`): `EINTR` if a handler runs, else the
942            // kernel's restart. As Linux's own `nanosleep`, a relative sleep
943            // returns `ERESTART_RESTARTBLOCK` and keeps its deadline for the
944            // `restart_syscall` the kernel runs only when no handler ran
945            // (`helpers::RestartBlock`, `resume_nanosleep`), so a new call,
946            // from a handler or a retry, cannot take it. An absolute one
947            // returns `ERESTARTNOHAND`: re-executed, it reads the same target.
948            if call.flags() & libc::TIMER_ABSTIME != 0 {
949                return Err(reverie::Error::Errno(Errno::ERESTARTNOHAND));
950            }
951            let result = Err(reverie::Error::Errno(Errno::ERESTART_RESTARTBLOCK));
952            crate::syscalls::helpers::keep_restart_block(
953                guest,
954                &result,
955                crate::syscalls::helpers::RestartCall::Nanosleep(call),
956                Some(target_time),
957            )
958            .await;
959            return result;
960        }
961        Err(reverie::Error::Errno(Errno::EINTR))
962    }
963
964    /// The kernel's `restart_syscall` of a relative `nanosleep` that ended for
965    /// a claimed `SIGCHLD` no handler ran for (`helpers::RestartCall::Nanosleep`).
966    /// Like Linux's restart block, it keeps the deadline it already has and
967    /// does not read the request again, which another thread may have changed.
968    pub(crate) async fn resume_nanosleep<R: Guest<Self>>(
969        &self,
970        guest: &mut R,
971        call: NanosleepFamily,
972        deadline: LogicalTime,
973    ) -> Result<i64, Error> {
974        let request = Self::sleep_request_abs(guest, deadline).await;
975        self.wait_and_return(guest, request, call).await
976    }
977
978    /// clock_nanosleep and nanosleep
979    pub async fn handle_nanosleep_family<R: Guest<Self>>(
980        &self,
981        guest: &mut R,
982        call: NanosleepFamily,
983    ) -> Result<i64, Error> {
984        if call.flags() > libc::TIMER_ABSTIME {
985            trace!("Unhandled clock_nanosleep flags, letting syscall through...");
986            // Linux reads only TIMER_ABSTIME from the flags, so the kernel runs
987            // this as a relative or absolute sleep and may leave a restart block.
988            return crate::syscalls::helpers::inject_keeping_kernel_restart(
989                guest,
990                Syscall::from(call),
991            )
992            .await;
993        }
994
995        // The CPU clocks are Detcore's own only where it virtualizes time;
996        // otherwise the host's clocks are read and slept on.
997        let clock_class = if self.cfg.virtualize_time {
998            // `clock_thread` has no `nsleep` (kernel/time/posix-cpu-timers.c:1666-1670
999            // at v6.16), so Linux answers EOPNOTSUPP before it reads the
1000            // request (`clock_nanosleep`, kernel/time/posix-timers.c:1385-1386).
1001            // glibc answers EINVAL itself, without the syscall.
1002            if raw_clock_id(call.clockid()) == libc::CLOCK_THREAD_CPUTIME_ID {
1003                return Err(Errno::EOPNOTSUPP.into());
1004            }
1005            cpu_clock::classify(raw_clock_id(call.clockid()))
1006        } else {
1007            ClockIdClass::Other
1008        };
1009
1010        let addr = call.req().ok_or(Errno::EFAULT)?;
1011        let t: Timespec = guest.memory().read_value(addr)?;
1012
1013        // Linux validates the requested interval BEFORE sleeping: nanosleep(2)
1014        // and clock_nanosleep(2) both fail EINVAL when tv_nsec is outside
1015        // [0, 999999999] or tv_sec is negative.
1016        //
1017        // Detcore skipped that check and fed the raw fields through `as u64`.
1018        // `Timespec` stores both as i64, so `tv_sec = -1` wrapped to
1019        // u64::MAX (~1.8e19 seconds) and became `SleepUntil(INDEFINITE)`: the
1020        // only guest thread parked with no deadline, the run queue emptied, and
1021        // `step2d_handle_empty_queue` deliberately never jumps the clock for an
1022        // indefinite waiter (doing so would also wake a `pause(2)`). The
1023        // container then died -- exit 1, "Sandbox container exited
1024        // unexpectedly" -- where Linux returns an errno and keeps running.
1025        //
1026        // A past *absolute* deadline is NOT an error and must still return 0,
1027        // so this rejects only malformed fields, never an early deadline.
1028        if t.tv_sec < 0 || t.tv_nsec < 0 || t.tv_nsec > 999_999_999 {
1029            return Err(Errno::EINVAL.into());
1030        }
1031
1032        let cpu_deadline_remaining = match clock_class {
1033            ClockIdClass::Other => None,
1034            ClockIdClass::NoCpuClock => return Err(Errno::EINVAL.into()),
1035            ClockIdClass::Cpu(clock) => self.cpu_clock_sleep(guest, call, clock, &t).await?,
1036        };
1037        if let Some(remaining) = cpu_deadline_remaining {
1038            return self.sleep_for(guest, call, remaining).await;
1039        }
1040
1041        match call.flags() {
1042            0 => {
1043                // Main's `sleep_for` is this arm's sequentialized path plus
1044                // the kernel run; `sleep_for` keeps the kernel restart
1045                // below, which is this change's non-sequentialized arm.
1046                let time =
1047                    Duration::from_secs(t.tv_sec as u64) + Duration::from_nanos(t.tv_nsec as u64);
1048                self.sleep_for(guest, call, time).await
1049            }
1050            libc::TIMER_ABSTIME => {
1051                let target_time = LogicalTime::from_secs(t.tv_sec as u64)
1052                    + LogicalTime::from_nanos(t.tv_nsec as u64);
1053                if self.cfg.sequentialize_threads {
1054                    if self.cfg.virtualize_time {
1055                        let request = Self::sleep_request_abs(guest, target_time).await;
1056                        trace!(
1057                            "nanosleep setting absolute time {:?} to yield request {:?}",
1058                            target_time, &request
1059                        );
1060                        self.wait_and_return(guest, request, call).await
1061                    } else {
1062                        // TODO T124594597: Record-replay case here, need better ideas to enable proper handling of this case.
1063                        error!(
1064                            "Sequentializing but not virtualizing, so can't rely on passed abs time, especially when replaying a recording, just yelding"
1065                        );
1066                        let request = Self::yield_request(guest);
1067                        self.wait_and_return(guest, request, call).await
1068                    }
1069                } else if self.cfg.virtualize_time {
1070                    trace!(
1071                        "Not sequentializing, but virtualizing so calculating relative time and invoking nanosleep..."
1072                    );
1073                    let relative_ts = Self::relative_time_from_abs_target(guest, target_time).await;
1074                    let mut stack = guest.stack().await;
1075                    let req = stack.push(relative_ts);
1076                    stack.commit()?;
1077                    let modified_call = syscalls::Nanosleep::new().with_req(Some(req));
1078                    // Linux restarts an absolute sleep by running it again, but
1079                    // this relative one keeps the host end the kernel computed,
1080                    // so it restarts from the kernel's restart block. Running
1081                    // the absolute call again would wait the whole interval
1082                    // again: logical time stands still while the thread sleeps
1083                    // in the kernel. The block holds no pointer to the request
1084                    // on the stack, and no `rem`.
1085                    crate::syscalls::helpers::inject_keeping_kernel_restart(guest, modified_call)
1086                        .await
1087                } else {
1088                    trace!(
1089                        "Not sequentializing threads not virtualizing, letting nanosleep through..."
1090                    );
1091                    Ok(guest.inject(Syscall::from(call)).await?)
1092                }
1093            }
1094            _ => unreachable!("Unexpected, unhandled flag value"),
1095        }
1096    }
1097
1098    /// Sleep for `time`: on the virtual clock where threads are
1099    /// sequentialized, otherwise in the kernel on the call's own clock. A
1100    /// relative call goes to the kernel as it is. An absolute CPU-clock call,
1101    /// which `cpu_clock_sleep` made relative to Detcore's reading of the
1102    /// clock, goes as a relative sleep for the rest.
1103    async fn sleep_for<G: Guest<Self>>(
1104        &self,
1105        guest: &mut G,
1106        call: NanosleepFamily,
1107        time: Duration,
1108    ) -> Result<i64, Error> {
1109        if self.cfg.sequentialize_threads {
1110            let request = Self::sleep_request(guest, time).await;
1111            trace!(
1112                "nanosleep adding delta {:?} to yield request {:?}",
1113                time, &request
1114            );
1115            return self.wait_and_return(guest, request, call).await;
1116        }
1117        trace!("Not sequentializing threads, letting nanosleep through...");
1118        if call.flags() & libc::TIMER_ABSTIME == 0 {
1119            // A kernel-run relative sleep keeps the kernel's restart
1120            // block, as in the handlers this change converted.
1121            return crate::syscalls::helpers::inject_keeping_kernel_restart(
1122                guest,
1123                Syscall::from(call),
1124            )
1125            .await;
1126        }
1127        let mut stack = guest.stack().await;
1128        let req = stack.push(Timespec {
1129            tv_sec: time.as_secs() as i64,
1130            tv_nsec: time.subsec_nanos() as i64,
1131        });
1132        stack.commit()?;
1133        let relative = syscalls::ClockNanosleep::new()
1134            .with_clockid(call.clockid())
1135            .with_flags(0)
1136            .with_req(Some(req))
1137            .with_rem(None);
1138        // The converted relative sleep keeps the kernel's restart block
1139        // too: restarting the absolute call would wait the whole interval
1140        // again while logical time stands still.
1141        crate::syscalls::helpers::inject_keeping_kernel_restart(guest, relative).await
1142    }
1143
1144    /// Linux's CPU-clock sleep (`posix_cpu_nsleep`,
1145    /// kernel/time/posix-cpu-timers.c:1570-1595 at v6.16) for a `clock`
1146    /// Detcore reads: EINVAL for the caller's own thread's clock (:1579-1582)
1147    /// and for a clock of no live task, as `posix_cpu_timer_create` answers
1148    /// (:386-397). Linux sleeps until the clock's task has used the CPU time
1149    /// requested, which only its other threads can spend while it sleeps.
1150    /// Detcore runs one thread at a time, so those threads spend CPU time at
1151    /// the virtual clock's rate, and a CPU-clock sleep counts down on the
1152    /// virtual clock, as it always has. `None` is a relative sleep, which
1153    /// takes the ordinary path. An absolute deadline is made relative to the
1154    /// clock's current reading, the time clock_gettime reads for it
1155    /// ([`cpu_sleep_remaining`]); this needs the reading, so a deadline on
1156    /// another process's clock is refused (`cpu_clock_reading`).
1157    async fn cpu_clock_sleep<G: Guest<Self>>(
1158        &self,
1159        guest: &mut G,
1160        call: NanosleepFamily,
1161        clock: cpu_clock::CpuClock,
1162        request: &Timespec,
1163    ) -> Result<Option<Duration>, Error> {
1164        let task = self
1165            .cpu_clock_task(
1166                guest,
1167                Sysno::clock_nanosleep,
1168                clock.owner,
1169                ClockLookup::Other,
1170            )
1171            .await?;
1172        if task == ClockTask::OwnThread {
1173            return Err(Errno::EINVAL.into());
1174        }
1175        if call.flags() & libc::TIMER_ABSTIME == 0 {
1176            return Ok(None);
1177        }
1178        let now = self
1179            .cpu_clock_reading(guest, Sysno::clock_nanosleep, task, clock.kind)
1180            .await?;
1181        Ok(Some(cpu_sleep_remaining(request, now)))
1182    }
1183
1184    async fn relative_time_from_abs_target<G: Guest<Self>>(
1185        guest: &mut G,
1186        target_time: LogicalTime,
1187    ) -> Timespec {
1188        let base_time = thread_observe_time(guest).await;
1189
1190        // An absolute deadline already in the past is NOT an error on Linux --
1191        // clock_nanosleep(TIMER_ABSTIME) simply returns 0 without sleeping.
1192        // `LogicalTime`'s `Sub` is a plain subtraction (unlike its `Add` impls,
1193        // which saturate deliberately), so `target_time - base_time` underflows
1194        // for a past deadline: a debug build panics with "attempt to subtract
1195        // with overflow", and a release build wraps to an enormous interval --
1196        // the same effectively-indefinite sleep this handler exists to avoid.
1197        //
1198        // Clamped here rather than by making the shared operator saturate,
1199        // because this is the only subtraction of two `LogicalTime`s in the
1200        // tree and a silently-saturating operator could hide a real underflow
1201        // in some future caller.
1202        let relative_logical = if target_time <= base_time {
1203            LogicalTime::from_nanos(0)
1204        } else {
1205            target_time - base_time
1206        };
1207
1208        Timespec {
1209            tv_sec: relative_logical.as_secs() as i64,
1210            tv_nsec: relative_logical.subsec_nanos() as i64,
1211        }
1212    }
1213
1214    /// Whether a POSIX timer notifying with `signo` registers its expirations
1215    /// with the scheduler. A standard signal always does. A real-time signal
1216    /// (32 to 64; glibc's SIGEV_THREAD timers use one through SIGEV_THREAD_ID)
1217    /// cannot be delivered by Detcore, whose signal model carries nix's `Signal`
1218    /// (https://github.com/rrnewton/hermit/issues/3893). Creating, arming, reading
1219    /// and deleting such a timer still behave as on Linux; only an expiration is
1220    /// unserviceable. A fail-closed run registers it anyway, and the scheduler
1221    /// refuses the run by name if it ever comes due; a permissive run
1222    /// (`--allow-unsupported-syscalls`) leaves it unregistered, so it never fires.
1223    fn posix_timer_expiry_is_registered(&self, signo: i32) -> bool {
1224        Signal::try_from(signo).is_ok() || self.cfg.panic_on_unsupported_syscalls
1225    }
1226
1227    // AUTONOMOUS-BOT-IMPLEMENTED
1228    // TODO-HUMAN-REVIEW(#869)
1229    /// timer_create: allocate a per-process POSIX timer and hand back a
1230    /// deterministic id, retaining any scheduler-deliverable signal and, for
1231    /// `SIGEV_THREAD_ID`, the thread it notifies. The notification is checked
1232    /// as Linux's `good_sigevent` does: `SIGEV_SIGNAL` and `SIGEV_THREAD` (which
1233    /// the kernel treats alike; libc implements the thread itself) need a
1234    /// signal from 1 to 64; `SIGEV_THREAD_ID` needs, first, a thread of the
1235    /// caller's own process (<https://github.com/rrnewton/hermit/issues/4164>);
1236    /// any other value is EINVAL.
1237    pub async fn handle_timer_create<G: Guest<Self>>(
1238        &self,
1239        guest: &mut G,
1240        call: syscalls::TimerCreate,
1241    ) -> Result<i64, Error> {
1242        // The kernel writes the new timer id here; a null pointer is EFAULT.
1243        let timerid_ptr = call.timerid().ok_or(Errno::EFAULT)?;
1244        let clockid = call.clockid();
1245        let (signo, thread, value) = if let Some(event_ptr) = call.sevp() {
1246            // Only the plain fields: `sigevent` holds a pointer, which must not
1247            // be kept across the query below. The value is kept as the 64 bits
1248            // Linux copies into `si_value`.
1249            let (notify, signo, named, value) = {
1250                let event: libc::sigevent = guest.memory().read_value(event_ptr)?;
1251                (
1252                    event.sigev_notify,
1253                    event.sigev_signo,
1254                    event.sigev_notify_thread_id,
1255                    event.sigev_value.sival_ptr as usize as u64,
1256                )
1257            };
1258            // A reserved in-guest signal: Linux answers for the clock right
1259            // after copying the sigevent, before it looks at the notification
1260            // (`do_timer_create`), so an unsupported clock is that answer even
1261            // when the notification is invalid too
1262            // (`timer_create_clock_refusal`).
1263            if guest.config().reserves_in_guest_signal(signo.into())
1264                && let Some(errno) = timer_create_clock_refusal(clockid)
1265            {
1266                return Err(errno.into());
1267            }
1268            let thread = match notify {
1269                libc::SIGEV_NONE => None,
1270                libc::SIGEV_SIGNAL | libc::SIGEV_THREAD => None,
1271                reverie::syscalls::linux_abi::SIGEV_THREAD_ID => {
1272                    match posix_timer_thread(guest, named).await {
1273                        PosixTimerThread::Thread(thread) => Some(thread),
1274                        PosixTimerThread::NotInGroup => return Err(Errno::EINVAL.into()),
1275                        PosixTimerThread::NestedNamespace => {
1276                            tracing::error!(
1277                                "[detcore, dtid {}] timer_create with SIGEV_THREAD_ID is not supported in a nested PID namespace: the thread id is a pid of that namespace, which Detcore does not translate (https://github.com/rrnewton/hermit/issues/4155)",
1278                                guest.thread_state().dettid,
1279                            );
1280                            return self
1281                                .refuse_unserviceable_operation(
1282                                    guest,
1283                                    Sysno::timer_create,
1284                                    Errno::ENOSYS,
1285                                )
1286                                .await;
1287                        }
1288                    }
1289                }
1290                _ => return Err(Errno::EINVAL.into()),
1291            };
1292            if notify == libc::SIGEV_NONE {
1293                (None, None, Some(value))
1294            } else if !(1..=64).contains(&signo) {
1295                return Err(Errno::EINVAL.into());
1296            } else {
1297                (Some(signo), thread, Some(value))
1298            }
1299        } else {
1300            (Some(libc::SIGALRM), None, None)
1301        };
1302        // A reserved in-guest signal as the timer's notification signal, for
1303        // each notification that delivers one (`SIGEV_SIGNAL`, `SIGEV_THREAD`,
1304        // `SIGEV_THREAD_ID`), after Linux's answers for the clock and the
1305        // sigevent above. With no `sigevent` the signal is SIGALRM, which is
1306        // never reserved.
1307        if let Some(signo) = signo
1308            && guest.config().reserves_in_guest_signal(signo.into())
1309        {
1310            Self::refuse_reserved_signal_arming(
1311                guest,
1312                crate::refused_signal_controls::ReservedArming::TimerCreate,
1313                signo.into(),
1314            )?;
1315        }
1316        // `None` for a real-time signal (32 to 64): see `handle_timer_settime`.
1317        let signal = signo.and_then(|signo| Signal::try_from(signo).ok());
1318        if signal == Some(Signal::SIGALRM) {
1319            refuse_sigalrm(guest, SigalrmControl::ArmProducer).await?;
1320        }
1321        let on_cpu_clock = matches!(
1322            cpu_clock::classify(raw_clock_id(clockid)),
1323            ClockIdClass::Cpu(_)
1324        );
1325        if signo == Some(libc::SIGKILL) {
1326            crate::reserved_input::expose_global(guest, "posix-timer-sigkill")?;
1327        }
1328        let id = {
1329            let mut timers = guest.thread_state().posix_timers.lock().unwrap();
1330            timers.create(signo, thread, value, on_cpu_clock)
1331        };
1332        guest
1333            .memory()
1334            .write_value(timerid_ptr, &(id as libc::c_int))?;
1335        // The process has a POSIX timer on this signal from its creation, armed
1336        // or not, which decides how a kept send standing on another sender's
1337        // record is classified (https://github.com/rrnewton/hermit/issues/4262).
1338        if crate::scheduler::discarded_at_send::records(guest.config())
1339            && let Some(signo) = signo
1340            && (1..32).contains(&signo)
1341        {
1342            crate::tool_global::discarded_signal(
1343                guest,
1344                crate::scheduler::discarded_at_send::DiscardedSignalControl::TimerCreated {
1345                    signal: signo,
1346                },
1347            )
1348            .await;
1349        }
1350        detlog!(
1351            "[dtid {}] timer_create(clockid={:?}) => deterministic timer id {}, signal {:?}, thread {:?}",
1352            guest.thread_state().dettid,
1353            clockid,
1354            id,
1355            signal,
1356            thread,
1357        );
1358        Ok(0)
1359    }
1360
1361    // AUTONOMOUS-BOT-IMPLEMENTED
1362    // TODO-HUMAN-REVIEW(#869)
1363    /// timer_settime: arm or disarm a timer against the deterministic virtual
1364    /// clock. The old arming is reported through `old_value` when requested.
1365    pub async fn handle_timer_settime<G: Guest<Self>>(
1366        &self,
1367        guest: &mut G,
1368        call: syscalls::TimerSettime,
1369    ) -> Result<i64, Error> {
1370        let id = call.timerid();
1371        let new_ptr = call.new_value().ok_or(Errno::EINVAL)?;
1372        let new: libc::itimerspec = guest.memory().read_value(new_ptr)?;
1373        let interval_ns = timespec_to_ns(new.it_interval);
1374        let value_ns = timespec_to_ns(new.it_value);
1375
1376        // A CPU clock's absolute expiration is a CPU time of the task the
1377        // timer was created for (`posix_cpu_timer_set`,
1378        // kernel/time/posix-cpu-timers.c:622-739 at v6.16), which Detcore's
1379        // timers, counting down on the virtual clock, do not record: refused
1380        // rather than read as a virtual time that has long passed.
1381        if self.cfg.virtualize_time
1382            && value_ns != 0
1383            && call.flags() & libc::TIMER_ABSTIME != 0
1384            && guest
1385                .thread_state()
1386                .posix_timers
1387                .lock()
1388                .unwrap()
1389                .on_cpu_clock(id)
1390        {
1391            return Err(self
1392                .refuse_cpu_clock(
1393                    guest,
1394                    Sysno::timer_settime,
1395                    "an absolute expiration on a CPU-clock timer: Detcore's timers count down on the virtual clock and do not record the task whose CPU time an absolute expiration names",
1396                )
1397                .await);
1398        }
1399
1400        let now = thread_observe_time(guest).await;
1401        let deadline = if value_ns == 0 {
1402            None
1403        } else if call.flags() & libc::TIMER_ABSTIME != 0 {
1404            // Absolute expiration is interpreted against the same virtual clock.
1405            Some(LogicalTime::from_nanos(value_ns))
1406        } else {
1407            Some(now + Duration::from_nanos(value_ns))
1408        };
1409
1410        let (old, signal_number, thread, value) = {
1411            let mut timers = guest.thread_state().posix_timers.lock().unwrap();
1412            let old = timers.settime(id, interval_ns, deadline, now);
1413            let signal = timers.signal(id);
1414            (
1415                old,
1416                signal,
1417                timers.thread(id),
1418                timers.value(id).unwrap_or(0),
1419            )
1420        };
1421        let (mut old_remaining_ns, old_interval_ns) = old.ok_or(Errno::EINVAL)?;
1422        let signal_number = signal_number.ok_or(Errno::EINVAL)?;
1423        // The old value is the timer's remaining time as `timer_gettime`
1424        // reads it now, from the scheduler where it keeps the timer's phase
1425        // (4262 design §5).
1426        if let Some((Some(remaining), _)) = posix_timer_readout(guest, id, now).await {
1427            old_remaining_ns = remaining.as_nanos();
1428        }
1429
1430        // Linux changes the timer, its generation and its overrun before it
1431        // copies the old value out (`do_timer_settime`), and an EFAULT there
1432        // undoes none of it, so the scheduler is told first (the Codex review
1433        // of https://github.com/rrnewton/hermit/pull/4491, P2-2).
1434        if let Some(signo) = signal_number {
1435            if self.posix_timer_expiry_is_registered(signo) {
1436                register_posix_timer(
1437                    guest,
1438                    id,
1439                    deadline,
1440                    LogicalTime::from_nanos(interval_ns),
1441                    PosixTimerNotification {
1442                        sig: SigWrapper(signo),
1443                        thread,
1444                        value,
1445                        deleted: false,
1446                    },
1447                )
1448                .await;
1449            } else if deadline.is_some() {
1450                tracing::error!(
1451                    "[detcore, dtid {}] POSIX timer {} notifies with real-time signal {}, which Detcore does not deliver from a timer; it is armed but will never fire",
1452                    guest.thread_state().dettid,
1453                    id,
1454                    signo,
1455                );
1456            }
1457        }
1458
1459        if let Some(old_ptr) = call.old_value() {
1460            let old_spec = libc::itimerspec {
1461                it_interval: ns_to_timespec(old_interval_ns),
1462                it_value: ns_to_timespec(old_remaining_ns),
1463            };
1464            guest.memory().write_value(old_ptr, &old_spec)?;
1465        }
1466
1467        detlog!(
1468            "[dtid {}] timer_settime(id={}, interval_ns={}, value_ns={}) armed against virtual clock",
1469            guest.thread_state().dettid,
1470            id,
1471            interval_ns,
1472            value_ns,
1473        );
1474        Ok(0)
1475    }
1476
1477    /// timer_gettime: report the time remaining until the next expiration and
1478    /// the reload interval, both computed from the virtual clock.
1479    pub async fn handle_timer_gettime<G: Guest<Self>>(
1480        &self,
1481        guest: &mut G,
1482        call: syscalls::TimerGettime,
1483    ) -> Result<i64, Error> {
1484        let id = call.timerid();
1485        let value_ptr = call.value().ok_or(Errno::EFAULT)?;
1486        let now = thread_observe_time(guest).await;
1487        let cur = {
1488            let timers = guest.thread_state().posix_timers.lock().unwrap();
1489            timers.gettime(id, now)
1490        };
1491        let (mut remaining_ns, interval_ns) = cur.ok_or(Errno::EINVAL)?;
1492        // Where the scheduler coalesces timers, it knows whether this one
1493        // waits for the dequeue of its signal (4262 design §5).
1494        if let Some((Some(remaining), _)) = posix_timer_readout(guest, id, now).await {
1495            remaining_ns = remaining.as_nanos();
1496        }
1497        let spec = libc::itimerspec {
1498            it_interval: ns_to_timespec(interval_ns),
1499            it_value: ns_to_timespec(remaining_ns),
1500        };
1501        guest.memory().write_value(value_ptr, &spec)?;
1502        Ok(0)
1503    }
1504
1505    /// timer_getoverrun: the expirations the timer's last delivered signal
1506    /// missed (`it_overrun_last`), where the scheduler coalesces timers
1507    /// (<https://github.com/rrnewton/hermit/issues/4262>); 0 elsewhere.
1508    pub async fn handle_timer_getoverrun<G: Guest<Self>>(
1509        &self,
1510        guest: &mut G,
1511        call: syscalls::TimerGetoverrun,
1512    ) -> Result<i64, Error> {
1513        let id = call.timerid();
1514        let exists = guest
1515            .thread_state()
1516            .posix_timers
1517            .lock()
1518            .unwrap()
1519            .contains(id);
1520        if !exists {
1521            return Err(Errno::EINVAL.into());
1522        }
1523        // The overrun is the scheduler's record alone, not a function of the
1524        // caller's time, which is not observed here.
1525        Ok(posix_timer_readout(guest, id, LogicalTime::ZERO)
1526            .await
1527            .map_or(0, |(_, overrun)| overrun as i64))
1528    }
1529
1530    // AUTONOMOUS-BOT-IMPLEMENTED
1531    // TODO-HUMAN-REVIEW(#869)
1532    /// timer_delete: destroy a timer created by `timer_create`.
1533    pub async fn handle_timer_delete<G: Guest<Self>>(
1534        &self,
1535        guest: &mut G,
1536        call: syscalls::TimerDelete,
1537    ) -> Result<i64, Error> {
1538        let id = call.timerid();
1539        let signal_number = guest
1540            .thread_state()
1541            .posix_timers
1542            .lock()
1543            .unwrap()
1544            .signal(id)
1545            .ok_or(Errno::EINVAL)?;
1546        let existed = {
1547            let mut timers = guest.thread_state().posix_timers.lock().unwrap();
1548            timers.remove(id)
1549        };
1550        if existed {
1551            if let Some(signo) = signal_number
1552                && self.posix_timer_expiry_is_registered(signo)
1553            {
1554                register_posix_timer(
1555                    guest,
1556                    id,
1557                    None,
1558                    LogicalTime::ZERO,
1559                    PosixTimerNotification {
1560                        sig: SigWrapper(signo),
1561                        thread: None,
1562                        value: 0,
1563                        deleted: true,
1564                    },
1565                )
1566                .await;
1567            }
1568            detlog!(
1569                "[dtid {}] timer_delete(id={})",
1570                guest.thread_state().dettid,
1571                id,
1572            );
1573            Ok(0)
1574        } else {
1575            Err(Errno::EINVAL.into())
1576        }
1577    }
1578}
1579
1580/// The scheduler's remaining time (`None`: the caller's own answer stands)
1581/// and overrun of the calling process's POSIX timer `id` at `now`, where it
1582/// keeps them (`DiscardedSignalControl::TimerReadout`); `None` elsewhere.
1583async fn posix_timer_readout<G: Guest<Detcore<T>>, T: RecordOrReplay>(
1584    guest: &mut G,
1585    id: i32,
1586    now: LogicalTime,
1587) -> Option<(Option<LogicalTime>, i32)> {
1588    use crate::scheduler::discarded_at_send::DiscardedSignalAnswer;
1589    use crate::scheduler::discarded_at_send::DiscardedSignalControl;
1590    if !crate::scheduler::discarded_at_send::records(guest.config()) {
1591        return None;
1592    }
1593    match crate::tool_global::discarded_signal(
1594        guest,
1595        DiscardedSignalControl::TimerReadout { timer: id, now },
1596    )
1597    .await
1598    {
1599        DiscardedSignalAnswer::TimerReadout { remaining, overrun } => Some((remaining, overrun)),
1600        _ => None,
1601    }
1602}
1603
1604#[cfg(test)]
1605mod tests {
1606    use super::*;
1607
1608    /// Linux's clock answer to `timer_create`, which a reserved-signal refusal
1609    /// must not come before: EINVAL for an id with no clock, EOPNOTSUPP for a
1610    /// clock without timers, nothing for the clocks with timers and for the
1611    /// ids whose answer depends on the host or the process they name.
1612    #[test]
1613    fn timer_create_clock_refusal_matches_linuxs_clock_table() {
1614        use reverie::syscalls::FromToRaw;
1615        let refusal = |id: i32| timer_create_clock_refusal(ClockId::from_raw(id as _));
1616        for id in [
1617            libc::CLOCK_REALTIME,
1618            libc::CLOCK_MONOTONIC,
1619            libc::CLOCK_PROCESS_CPUTIME_ID,
1620            libc::CLOCK_THREAD_CPUTIME_ID,
1621            libc::CLOCK_BOOTTIME,
1622            libc::CLOCK_REALTIME_ALARM,
1623            libc::CLOCK_BOOTTIME_ALARM,
1624            libc::CLOCK_TAI,
1625            -2,
1626        ] {
1627            assert_eq!(refusal(id), None, "{id}");
1628        }
1629        // FD_TO_CLOCKID(fd), ((~fd) << 3) | CLOCKFD, for descriptors 3 and 0:
1630        // clock descriptors, which have no timers.
1631        let clock_descriptor = |fd: i32| (!fd << 3) | 3;
1632        for id in [
1633            libc::CLOCK_MONOTONIC_RAW,
1634            libc::CLOCK_REALTIME_COARSE,
1635            libc::CLOCK_MONOTONIC_COARSE,
1636            clock_descriptor(3),
1637            clock_descriptor(0),
1638        ] {
1639            assert_eq!(refusal(id), Some(Errno::EOPNOTSUPP), "{id}");
1640        }
1641        // CPU clocks of a process (pid 1, CPUCLOCK_SCHED) and of a thread
1642        // (perthread bit) keep `None`: their answer depends on the task.
1643        for id in [(!1 << 3) | 2, (!1 << 3) | 4 | 2] {
1644            assert_eq!(refusal(id), None, "{id}");
1645        }
1646        // Per-thread CPU-clock bits with CPUCLOCK_WHICH 3: no such clock.
1647        for id in [10, 12, 99, (!1 << 3) | 7, (!0 << 3) | 7] {
1648            assert_eq!(refusal(id), Some(Errno::EINVAL), "{id}");
1649        }
1650    }
1651
1652    /// An absolute CPU-clock deadline waits for the CPU time still to come,
1653    /// and none once the clock has passed it.
1654    #[test]
1655    fn an_absolute_cpu_deadline_waits_for_the_rest() {
1656        let deadline = Timespec {
1657            tv_sec: 2,
1658            tv_nsec: 500,
1659        };
1660        let at = LogicalTime::from_nanos;
1661        assert_eq!(
1662            cpu_sleep_remaining(&deadline, at(1_999_999_000)),
1663            Duration::from_nanos(1_500)
1664        );
1665        assert_eq!(
1666            cpu_sleep_remaining(&deadline, at(2_000_000_500)),
1667            Duration::ZERO
1668        );
1669        assert_eq!(
1670            cpu_sleep_remaining(&deadline, at(9_000_000_000)),
1671            Duration::ZERO
1672        );
1673        let far = Timespec {
1674            tv_sec: i64::MAX,
1675            tv_nsec: 999_999_999,
1676        };
1677        assert_eq!(
1678            cpu_sleep_remaining(&far, LogicalTime::ZERO),
1679            Duration::from_nanos(u64::MAX)
1680        );
1681    }
1682
1683    #[test]
1684    fn timex_policy_distinguishes_queries_from_mutations() {
1685        assert!(timex_mode_is_query(0));
1686        assert!(timex_mode_is_query(libc::ADJ_OFFSET_SS_READ));
1687        assert!(!timex_mode_is_query(libc::ADJ_OFFSET));
1688        assert!(!timex_mode_is_query(libc::ADJ_FREQUENCY));
1689    }
1690
1691    #[test]
1692    fn timex_snapshot_is_unsynchronized_and_uses_virtual_time() {
1693        let tx = deterministic_timex(Timespec {
1694            tv_sec: 123,
1695            tv_nsec: 456_789_000,
1696        });
1697        assert_eq!(tx.status, libc::STA_UNSYNC);
1698        assert_eq!(tx.tick, 10_000);
1699        assert_eq!(tx.time.tv_sec, 123);
1700        assert_eq!(tx.time.tv_usec, 456_789);
1701    }
1702
1703    #[test]
1704    fn interrupted_sleep_remaining_time_floors_at_zero() {
1705        let target = LogicalTime::from_nanos(1_000);
1706
1707        assert_eq!(
1708            remaining_sleep_duration(target, LogicalTime::from_nanos(750)),
1709            Duration::from_nanos(250)
1710        );
1711        assert_eq!(remaining_sleep_duration(target, target), Duration::ZERO);
1712        assert_eq!(
1713            remaining_sleep_duration(target, LogicalTime::from_nanos(1_250)),
1714            Duration::ZERO
1715        );
1716    }
1717
1718    mod failed_gettimeofday_tv {
1719        use super::*;
1720
1721        fn failure(error: Error) -> TvRepairFailure {
1722            match error {
1723                Error::Tool(error) => *error
1724                    .downcast_ref::<TvRepairFailure>()
1725                    .expect("a typed repair failure"),
1726                other => panic!("expected a Tool error, got {other:?}"),
1727            }
1728        }
1729
1730        #[test]
1731        fn successful_time_store_probe_requires_an_overwrite() {
1732            assert_eq!(
1733                classify_time_store_probe("tv_sec", Ok(1)).unwrap(),
1734                TimeStoreProbe::Stored
1735            );
1736        }
1737
1738        #[test]
1739        fn efault_time_store_probe_stops_without_an_overwrite() {
1740            assert_eq!(
1741                classify_time_store_probe("tv_usec", Err(Errno::EFAULT)).unwrap(),
1742                TimeStoreProbe::Stopped
1743            );
1744        }
1745
1746        #[test]
1747        fn any_control_probe_error_means_the_efault_was_not_a_store_fault() {
1748            require_native_time_control_probe("tv_sec", Ok(1_767_225_600)).unwrap();
1749            for errno in [Errno::EFAULT, Errno::EPERM, Errno::ENOSYS] {
1750                let error = require_native_time_control_probe("tv_usec", Err(errno))
1751                    .expect_err("time(NULL) cannot fail natively");
1752                assert_eq!(
1753                    failure(error),
1754                    TvRepairFailure {
1755                        field: "tv_usec",
1756                        kind: TvRepairFailureKind::ControlProbeFailed(errno),
1757                    }
1758                );
1759            }
1760        }
1761
1762        #[test]
1763        fn a_stopped_word_must_keep_its_contents_and_readability() {
1764            assert_eq!(
1765                require_unchanged_stopped_word("tv_sec", Ok(7), Ok(7)).unwrap(),
1766                StoppedWord::Unchanged
1767            );
1768            for (before, after) in [(Errno::EFAULT, Errno::EFAULT), (Errno::EIO, Errno::EPERM)] {
1769                assert_eq!(
1770                    require_unchanged_stopped_word("tv_sec", Err(before), Err(after)).unwrap(),
1771                    StoppedWord::Unreadable
1772                );
1773            }
1774            for (before, after) in [
1775                (Ok(7), Ok(1_791_041_091)),
1776                (Ok(7), Err(Errno::EFAULT)),
1777                (Err(Errno::EFAULT), Ok(7)),
1778            ] {
1779                let error = require_unchanged_stopped_word("tv_usec", before, after)
1780                    .expect_err("a changed stopped word means the call stored it");
1781                assert_eq!(
1782                    failure(error),
1783                    TvRepairFailure {
1784                        field: "tv_usec",
1785                        kind: TvRepairFailureKind::StoppedWordChanged,
1786                    }
1787                );
1788            }
1789        }
1790
1791        #[test]
1792        fn an_unreadable_word_is_unstored_only_if_part_of_it_is_unmapped() {
1793            const PAGE: u64 = 0x1000;
1794            let two_pages = || Ok(vec![(3 * PAGE, 4 * PAGE), (2 * PAGE, 3 * PAGE)]);
1795            // Outside every mapping, and straddling either end of the mapped pages.
1796            for word in [1, 2 * PAGE - 4, 4 * PAGE - 4, 5 * PAGE, u64::MAX - 3] {
1797                require_unmapped_unreadable_word("tv_sec", two_pages(), word).unwrap();
1798            }
1799            // Inside one page, and across the boundary of two adjacent mappings.
1800            for word in [2 * PAGE, 3 * PAGE - 4, 4 * PAGE - 8] {
1801                let error = require_unmapped_unreadable_word("tv_usec", two_pages(), word)
1802                    .expect_err("a failed read of a mapped word is not a fault");
1803                assert_eq!(
1804                    failure(error),
1805                    TvRepairFailure {
1806                        field: "tv_usec",
1807                        kind: TvRepairFailureKind::StoppedWordUnreadable,
1808                    }
1809                );
1810            }
1811        }
1812
1813        #[test]
1814        fn an_unreadable_word_needs_a_readable_nonempty_map() {
1815            let unreadable = Err(Error::Errno(Errno::EPERM));
1816            for maps in [Ok(Vec::new()), unreadable] {
1817                let error = require_unmapped_unreadable_word("tv_sec", maps, 1)
1818                    .expect_err("without a map an unreadable word proves nothing");
1819                assert_eq!(
1820                    failure(error),
1821                    TvRepairFailure {
1822                        field: "tv_sec",
1823                        kind: TvRepairFailureKind::MapsUnavailable,
1824                    }
1825                );
1826            }
1827        }
1828
1829        #[test]
1830        fn other_time_store_probe_errors_fail_closed() {
1831            for errno in [Errno::ENOSYS, Errno::EPERM, Errno::EIO] {
1832                let error = classify_time_store_probe("tv_sec", Err(errno))
1833                    .expect_err("a non-EFAULT probe error must fail the repair");
1834                assert_eq!(
1835                    failure(error),
1836                    TvRepairFailure {
1837                        field: "tv_sec",
1838                        kind: TvRepairFailureKind::ProbeFailed(errno),
1839                    }
1840                );
1841            }
1842        }
1843
1844        #[test]
1845        fn overwrite_errors_and_nonexact_counts_fail_closed() {
1846            assert_eq!(
1847                failure(
1848                    require_complete_time_word_overwrite("tv_usec", 8, Err(Errno::EFAULT),)
1849                        .unwrap_err()
1850                ),
1851                TvRepairFailure {
1852                    field: "tv_usec",
1853                    kind: TvRepairFailureKind::OverwriteFailed(Errno::EFAULT),
1854                }
1855            );
1856            for reported in [0, 3, 7, 9] {
1857                assert_eq!(
1858                    failure(
1859                        require_complete_time_word_overwrite("tv_sec", 8, Ok(reported))
1860                            .unwrap_err()
1861                    ),
1862                    TvRepairFailure {
1863                        field: "tv_sec",
1864                        kind: TvRepairFailureKind::OverwriteCount {
1865                            expected: 8,
1866                            reported,
1867                        },
1868                    }
1869                );
1870            }
1871            require_complete_time_word_overwrite("tv_sec", 8, Ok(8)).unwrap();
1872
1873            require_live_time_store_probe(false).unwrap();
1874            assert_eq!(
1875                failure(require_live_time_store_probe(true).unwrap_err()),
1876                TvRepairFailure {
1877                    field: "tv",
1878                    kind: TvRepairFailureKind::ReplayMode,
1879                }
1880            );
1881        }
1882
1883        #[test]
1884        fn timeval_word_addresses_follow_kernel_order_and_overflow_fails_closed_only_for_probes() {
1885            assert_eq!(TIMEVAL_WORDS, [("tv_sec", 0), ("tv_usec", 8)]);
1886            let tv_addr = AddrMut::<Timeval>::from_raw(0x10_0000).unwrap();
1887            assert_eq!(
1888                timeval_word_addr("tv_sec", tv_addr, std::mem::offset_of!(Timeval, tv_sec))
1889                    .unwrap()
1890                    .as_raw(),
1891                tv_addr.as_raw()
1892            );
1893            assert_eq!(
1894                timeval_word_addr("tv_usec", tv_addr, std::mem::offset_of!(Timeval, tv_usec))
1895                    .unwrap()
1896                    .as_raw(),
1897                tv_addr.as_raw() + 8
1898            );
1899
1900            let overflowing = AddrMut::<Timeval>::from_raw(usize::MAX - 3).unwrap();
1901            let error = timeval_word_addr("tv_usec", overflowing, 8)
1902                .expect_err("overflowing field address must fail the repair");
1903            assert_eq!(
1904                failure(error),
1905                TvRepairFailure {
1906                    field: "tv_usec",
1907                    kind: TvRepairFailureKind::AddressOverflow,
1908                }
1909            );
1910
1911            // Checking a stopped word needs no probe, so a word past the end of
1912            // the address space is simply one no store reached.
1913            for (_, offset) in TIMEVAL_WORDS {
1914                assert_eq!(
1915                    stopped_timeval_word_addr(tv_addr, offset).map(|addr| addr.as_raw()),
1916                    Some(tv_addr.as_raw() + offset)
1917                );
1918            }
1919            // `gettimeofday((void *)-1, NULL)`: `tv_sec` is the last byte of
1920            // the address space and `tv_usec` has no address at all.
1921            let last = AddrMut::<Timeval>::from_raw(usize::MAX).unwrap();
1922            assert_eq!(
1923                stopped_timeval_word_addr(last, 0).map(|addr| addr.as_raw()),
1924                Some(usize::MAX)
1925            );
1926            assert!(stopped_timeval_word_addr(last, 8).is_none());
1927            assert!(stopped_timeval_word_addr(overflowing, 8).is_none());
1928        }
1929    }
1930}
1931
1932#[cfg(test)]
1933mod sleep_request_tests {
1934    use reverie::GlobalRPC;
1935    use reverie::GlobalTool;
1936    use reverie::Tid;
1937    use reverie::syscalls::Addr;
1938    use reverie::syscalls::LocalMemory;
1939    use reverie::syscalls::SyscallInfo;
1940
1941    use super::*;
1942    use crate::Config;
1943    use crate::GlobalState;
1944    use crate::ThreadState;
1945    use crate::scheduler::ends_a_due_sleep;
1946    use crate::tool_global::GlobalRequest;
1947    use crate::tool_global::GlobalResponse;
1948    use crate::types::DetPid;
1949
1950    /// The clock reading the coordinator answers.
1951    fn now() -> LogicalTime {
1952        LogicalTime::from_nanos(5_000_000)
1953    }
1954    const THREAD: DetPid = DetPid::from_raw(7);
1955
1956    /// A thread whose one RPC is the clock reading a relative sleep starts
1957    /// from (`thread_observe_time`), answered with `now()`.
1958    struct ClockReader {
1959        config: Config,
1960        thread: ThreadState<()>,
1961    }
1962
1963    impl ClockReader {
1964        fn new() -> Self {
1965            let config = Config::default();
1966            let mut thread = ThreadState::new(THREAD, &config, ());
1967            thread.detpid = Some(THREAD);
1968            Self { config, thread }
1969        }
1970    }
1971
1972    /// Building a sleep request takes no stack.
1973    struct NoStack;
1974    struct NoStackGuard;
1975    impl Drop for NoStackGuard {
1976        fn drop(&mut self) {}
1977    }
1978    impl Stack for NoStack {
1979        type StackGuard = NoStackGuard;
1980        fn size(&self) -> usize {
1981            panic!("building a sleep request must not use the guest stack")
1982        }
1983        fn capacity(&self) -> usize {
1984            panic!("building a sleep request must not use the guest stack")
1985        }
1986        fn push<'stack, T>(&mut self, _: T) -> Addr<'stack, T> {
1987            panic!("building a sleep request must not use the guest stack")
1988        }
1989        fn reserve<'stack, T>(&mut self) -> AddrMut<'stack, T> {
1990            panic!("building a sleep request must not use the guest stack")
1991        }
1992        fn commit(self) -> Result<Self::StackGuard, Errno> {
1993            panic!("building a sleep request must not use the guest stack")
1994        }
1995    }
1996
1997    #[reverie::tool]
1998    impl GlobalRPC<GlobalState> for ClockReader {
1999        async fn send_rpc(
2000            &self,
2001            message: <GlobalState as GlobalTool>::Request,
2002        ) -> <GlobalState as GlobalTool>::Response {
2003            match message.2 {
2004                GlobalRequest::GlobalTimeLowerBound => {
2005                    (None, GlobalResponse::GlobalTimeLowerBound(now()))
2006                }
2007                other => panic!("building a sleep request sent {other:?}"),
2008            }
2009        }
2010        fn config(&self) -> &Config {
2011            &self.config
2012        }
2013    }
2014
2015    #[reverie::tool]
2016    impl Guest<Detcore> for ClockReader {
2017        type Memory = LocalMemory;
2018        type Stack = NoStack;
2019
2020        fn tid(&self) -> Tid {
2021            Tid::from_raw(THREAD.as_raw())
2022        }
2023        fn pid(&self) -> Tid {
2024            self.tid()
2025        }
2026        fn ppid(&self) -> Option<Tid> {
2027            None
2028        }
2029        fn memory(&self) -> Self::Memory {
2030            panic!("building a sleep request must not read guest memory")
2031        }
2032        fn thread_state(&self) -> &ThreadState<()> {
2033            &self.thread
2034        }
2035        fn thread_state_mut(&mut self) -> &mut ThreadState<()> {
2036            &mut self.thread
2037        }
2038        async fn regs(&mut self) -> libc::user_regs_struct {
2039            panic!("building a sleep request must not read registers")
2040        }
2041        async fn stack(&mut self) -> Self::Stack {
2042            panic!("building a sleep request must not use the guest stack")
2043        }
2044        async fn daemonize(&mut self) {
2045            panic!("building a sleep request must not daemonize")
2046        }
2047        async fn inject<S: SyscallInfo>(&mut self, call: S) -> Result<i64, Errno> {
2048            panic!(
2049                "building a sleep request must not inject {:?}",
2050                call.number()
2051            )
2052        }
2053        async fn tail_inject<S: SyscallInfo>(&mut self, _: S) -> reverie::Never {
2054            panic!("building a sleep request must not retire the guest")
2055        }
2056        fn set_timer(&mut self, _: reverie::TimerSchedule) -> Result<(), Error> {
2057            panic!("building a sleep request must not set a timer")
2058        }
2059        fn set_timer_precise(&mut self, _: reverie::TimerSchedule) -> Result<(), Error> {
2060            panic!("building a sleep request must not set a timer")
2061        }
2062        fn read_clock(&mut self) -> Result<u64, Error> {
2063            panic!("building a sleep request must not read the clock")
2064        }
2065    }
2066
2067    /// `sleep_request`, which `nanosleep` and `clock_nanosleep` without
2068    /// `TIMER_ABSTIME` build their request with, marks a sleep of zero length
2069    /// (`usleep(0)` is `nanosleep` of zero) and no other: a yield idiom the
2070    /// scheduler must not take for a due sleep at its deadline
2071    /// (`ends_a_due_sleep`), so its turn counts toward a chaos slice. A sleep
2072    /// of 1 ns or 100 us is not marked and is a due sleep once its deadline has
2073    /// come, and so is an absolute sleep whose deadline is already now
2074    /// (`sleep_request_abs`).
2075    #[tokio::test]
2076    async fn only_a_relative_sleep_of_zero_is_a_zero_length_sleep() {
2077        for (length, zero_length) in [
2078            (Duration::ZERO, true),
2079            (Duration::from_nanos(1), false),
2080            (Duration::from_micros(100), false),
2081        ] {
2082            let mut guest = ClockReader::new();
2083            let request = <Detcore>::sleep_request(&mut guest, length).await;
2084            let deadline = now() + length;
2085            assert_eq!(request.zero_length_sleep, zero_length, "{length:?}");
2086            assert_eq!(
2087                request.resources.keys().collect::<Vec<_>>(),
2088                [&ResourceID::SleepUntil(deadline)],
2089                "{length:?}"
2090            );
2091            assert_eq!(
2092                ends_a_due_sleep(&request, deadline),
2093                !zero_length,
2094                "{length:?}: a due sleep at its deadline"
2095            );
2096        }
2097        let mut guest = ClockReader::new();
2098        let request = <Detcore>::sleep_request_abs(&mut guest, now()).await;
2099        assert!(!request.zero_length_sleep, "an absolute sleep");
2100        assert!(
2101            ends_a_due_sleep(&request, now()),
2102            "an absolute sleep at its deadline"
2103        );
2104    }
2105}