1use 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
55fn 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
68fn raw_clock_id(clockid: ClockId) -> i32 {
70 use reverie::syscalls::FromToRaw;
71 clockid.into_raw() as i32
72}
73
74fn 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 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
131fn 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
139fn 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
154fn 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
162fn timex_mode_is_query(modes: libc::c_uint) -> bool {
165 modes == 0 || modes == libc::ADJ_OFFSET_SS_READ
166}
167
168fn deterministic_timex(now: Timespec) -> libc::timex {
171 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
183pub(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#[derive(Debug, Clone, Copy, PartialEq, Eq)]
198struct TvRepairFailure {
199 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 ProbeFailed(Errno),
216 ControlProbeFailed(Errno),
220 StoppedWordChanged,
224 StoppedWordUnreadable,
229 MapsUnavailable,
232 OverwriteFailed(Errno),
235 OverwriteCount { expected: usize, reported: usize },
237 AddressOverflow,
239 ReplayMode,
242 #[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#[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#[cfg(target_arch = "x86_64")]
336#[derive(Debug, Clone, Copy, PartialEq, Eq)]
337enum StoppedWord {
338 Unchanged,
340 Unreadable,
343}
344
345#[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#[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#[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
422type 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#[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#[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#[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 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 pub async fn sleep_request_abs<G: Guest<Self>>(guest: &mut G, time: LogicalTime) -> Resources {
642 let resource = ResourceID::SleepUntil(time);
644 guest.thread_state().mk_request(resource, Permission::W)
645 }
646
647 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 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 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 pub fn priority_changepoint_request<G: Guest<Self>>(
673 guest: &mut G,
674 change_time: LogicalTime,
675 new_priority: Priority,
676 ) -> Resources {
677 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 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 let before = call.tv().map(|tp| snapshot_timeval_words(guest, tp.into()));
696
697 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 (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 #[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 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 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 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 if let Some(res) = call.res() {
802 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 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 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 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 request.fyi(crate::resources::NANOSLEEP_FYI);
871 let mut claimed = false;
872 loop {
873 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 self.stage_in_guest_fatal_alarm(guest).await;
896 return Err(Errno::EINTR.into());
897 }
898 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 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 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 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 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 return crate::syscalls::helpers::inject_keeping_kernel_restart(
989 guest,
990 Syscall::from(call),
991 )
992 .await;
993 }
994
995 let clock_class = if self.cfg.virtualize_time {
998 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 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 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 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 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 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 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 crate::syscalls::helpers::inject_keeping_kernel_restart(guest, relative).await
1142 }
1143
1144 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 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 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 pub async fn handle_timer_create<G: Guest<Self>>(
1238 &self,
1239 guest: &mut G,
1240 call: syscalls::TimerCreate,
1241 ) -> Result<i64, Error> {
1242 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 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 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 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 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 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 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 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 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 if let Some((Some(remaining), _)) = posix_timer_readout(guest, id, now).await {
1427 old_remaining_ns = remaining.as_nanos();
1428 }
1429
1430 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 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 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 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 Ok(posix_timer_readout(guest, id, LogicalTime::ZERO)
1526 .await
1527 .map_or(0, |(_, overrun)| overrun as i64))
1528 }
1529
1530 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
1580async 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 #[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 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 for id in [(!1 << 3) | 2, (!1 << 3) | 4 | 2] {
1644 assert_eq!(refusal(id), None, "{id}");
1645 }
1646 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 #[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 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 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 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 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 fn now() -> LogicalTime {
1952 LogicalTime::from_nanos(5_000_000)
1953 }
1954 const THREAD: DetPid = DetPid::from_raw(7);
1955
1956 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 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 #[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}