Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit f5e2f73

Browse files
RalfJungpvdrz
authored andcommitted
move clock stuff to separate file
1 parent ad69e0b commit f5e2f73

File tree

7 files changed

+154
-149
lines changed

7 files changed

+154
-149
lines changed

src/clock.rs

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
use std::sync::atomic::AtomicU64;
2+
use std::time::{Duration, Instant as StdInstant};
3+
4+
use rustc_data_structures::sync::Ordering;
5+
6+
use crate::*;
7+
8+
/// When using a virtual clock, this defines how many nanoseconds do we pretend
9+
/// are passing for each basic block.
10+
const NANOSECOND_PER_BASIC_BLOCK: u64 = 10;
11+
12+
#[derive(Debug)]
13+
pub struct Instant {
14+
kind: InstantKind,
15+
}
16+
17+
#[derive(Debug)]
18+
enum InstantKind {
19+
Host(StdInstant),
20+
Virtual { nanoseconds: u64 },
21+
}
22+
23+
/// A monotone clock used for `Instant` simulation.
24+
#[derive(Debug)]
25+
pub struct Clock {
26+
kind: ClockKind,
27+
}
28+
29+
#[derive(Debug)]
30+
enum ClockKind {
31+
Host {
32+
/// The "time anchor" for this machine's monotone clock.
33+
time_anchor: StdInstant,
34+
},
35+
Virtual {
36+
/// The "current virtual time".
37+
nanoseconds: AtomicU64,
38+
},
39+
}
40+
41+
impl Clock {
42+
/// Create a new clock based on the availability of communication with the host.
43+
pub fn new(communicate: bool) -> Self {
44+
let kind = if communicate {
45+
ClockKind::Host { time_anchor: StdInstant::now() }
46+
} else {
47+
ClockKind::Virtual { nanoseconds: 0.into() }
48+
};
49+
50+
Self { kind }
51+
}
52+
53+
/// Get the current time relative to this clock.
54+
pub fn get(&self) -> Duration {
55+
match &self.kind {
56+
ClockKind::Host { time_anchor } =>
57+
StdInstant::now().saturating_duration_since(*time_anchor),
58+
ClockKind::Virtual { nanoseconds } =>
59+
Duration::from_nanos(nanoseconds.load(Ordering::Relaxed)),
60+
}
61+
}
62+
63+
/// Let the time pass for a small interval.
64+
pub fn tick(&self) {
65+
match &self.kind {
66+
ClockKind::Host { .. } => {
67+
// Time will pass without us doing anything.
68+
}
69+
ClockKind::Virtual { nanoseconds } => {
70+
nanoseconds.fetch_add(NANOSECOND_PER_BASIC_BLOCK, Ordering::Relaxed);
71+
}
72+
}
73+
}
74+
75+
/// Sleep for the desired duration.
76+
pub fn sleep(&self, duration: Duration) {
77+
match &self.kind {
78+
ClockKind::Host { .. } => std::thread::sleep(duration),
79+
ClockKind::Virtual { nanoseconds } => {
80+
// Just pretend that we have slept for some time.
81+
nanoseconds.fetch_add(duration.as_nanos().try_into().unwrap(), Ordering::Relaxed);
82+
}
83+
}
84+
}
85+
86+
/// Compute `now + duration` relative to this clock.
87+
pub fn get_time_relative(&self, duration: Duration) -> Option<Instant> {
88+
match &self.kind {
89+
ClockKind::Host { .. } =>
90+
StdInstant::now()
91+
.checked_add(duration)
92+
.map(|instant| Instant { kind: InstantKind::Host(instant) }),
93+
ClockKind::Virtual { nanoseconds } =>
94+
nanoseconds
95+
.load(Ordering::Relaxed)
96+
.checked_add(duration.as_nanos().try_into().unwrap())
97+
.map(|nanoseconds| Instant { kind: InstantKind::Virtual { nanoseconds } }),
98+
}
99+
}
100+
101+
/// Compute `start + duration` relative to this clock where `start` is the instant of time when
102+
/// this clock was created.
103+
pub fn get_time_absolute(&self, duration: Duration) -> Option<Instant> {
104+
match &self.kind {
105+
ClockKind::Host { time_anchor } =>
106+
time_anchor
107+
.checked_add(duration)
108+
.map(|instant| Instant { kind: InstantKind::Host(instant) }),
109+
ClockKind::Virtual { .. } =>
110+
Some(Instant {
111+
kind: InstantKind::Virtual {
112+
nanoseconds: duration.as_nanos().try_into().unwrap(),
113+
},
114+
}),
115+
}
116+
}
117+
118+
/// Returns the duration until the given instant.
119+
pub fn duration_until(&self, instant: &Instant) -> Duration {
120+
match (&instant.kind, &self.kind) {
121+
(InstantKind::Host(instant), ClockKind::Host { .. }) =>
122+
instant.saturating_duration_since(StdInstant::now()),
123+
(
124+
InstantKind::Virtual { nanoseconds },
125+
ClockKind::Virtual { nanoseconds: current_ns },
126+
) =>
127+
Duration::from_nanos(nanoseconds.saturating_sub(current_ns.load(Ordering::Relaxed))),
128+
_ => panic!(),
129+
}
130+
}
131+
}

src/concurrency/thread.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ use rustc_target::spec::abi::Abi;
1616

1717
use crate::concurrency::data_race;
1818
use crate::concurrency::sync::SynchronizationState;
19-
use crate::shims::time::{Clock, Instant};
2019
use crate::*;
2120

2221
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
@@ -188,6 +187,17 @@ pub enum Time {
188187
RealTime(SystemTime),
189188
}
190189

190+
impl Time {
191+
/// How long do we have to wait from now until the specified time?
192+
fn get_wait_time(&self, clock: &Clock) -> Duration {
193+
match self {
194+
Time::Monotonic(instant) => clock.duration_until(instant),
195+
Time::RealTime(time) =>
196+
time.duration_since(SystemTime::now()).unwrap_or(Duration::new(0, 0)),
197+
}
198+
}
199+
}
200+
191201
/// Callbacks are used to implement timeouts. For example, waiting on a
192202
/// conditional variable with a timeout creates a callback that is called after
193203
/// the specified time and unblocks the thread. If another thread signals on the
@@ -489,7 +499,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
489499
for thread in self.threads.indices() {
490500
match self.timeout_callbacks.entry(thread) {
491501
Entry::Occupied(entry) =>
492-
if clock.get_wait_time(&entry.get().call_time) == Duration::new(0, 0) {
502+
if entry.get().call_time.get_wait_time(clock) == Duration::new(0, 0) {
493503
return Some((thread, entry.remove().callback));
494504
},
495505
Entry::Vacant(_) => {}
@@ -573,7 +583,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
573583
// at the time of the call".
574584
// <https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_timedwait.html>
575585
let potential_sleep_time =
576-
self.timeout_callbacks.values().map(|info| clock.get_wait_time(&info.call_time)).min();
586+
self.timeout_callbacks.values().map(|info| info.call_time.get_wait_time(clock)).min();
577587
if potential_sleep_time == Some(Duration::new(0, 0)) {
578588
return Ok(SchedulingAction::ExecuteTimeoutCallback);
579589
}

src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ extern crate rustc_session;
5151
extern crate rustc_span;
5252
extern crate rustc_target;
5353

54+
mod clock;
5455
mod concurrency;
5556
mod diagnostics;
5657
mod eval;
@@ -81,6 +82,7 @@ pub use crate::shims::time::EvalContextExt as _;
8182
pub use crate::shims::tls::{EvalContextExt as _, TlsData};
8283
pub use crate::shims::EvalContextExt as _;
8384

85+
pub use crate::clock::{Clock, Instant};
8486
pub use crate::concurrency::{
8587
data_race::{
8688
AtomicFenceOrd, AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd,
@@ -89,7 +91,7 @@ pub use crate::concurrency::{
8991
sync::{CondvarId, EvalContextExt as SyncEvalContextExt, MutexId, RwLockId},
9092
thread::{
9193
EvalContextExt as ThreadsEvalContextExt, SchedulingAction, ThreadId, ThreadManager,
92-
ThreadState,
94+
ThreadState, Time,
9395
},
9496
};
9597
pub use crate::diagnostics::{

src/machine.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use rustc_target::spec::abi::Abi;
2727

2828
use crate::{
2929
concurrency::{data_race, weak_memory},
30-
shims::{time::Clock, unix::FileHandler},
30+
shims::unix::FileHandler,
3131
*,
3232
};
3333

src/shims/time.rs

Lines changed: 3 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -1,145 +1,7 @@
1-
use std::sync::atomic::AtomicU64;
2-
use std::time::{Duration, Instant as StdInstant, SystemTime};
1+
use std::time::{Duration, SystemTime};
32

4-
use rustc_data_structures::sync::Ordering;
5-
6-
use crate::concurrency::thread::Time;
73
use crate::*;
84

9-
/// When using a virtual clock, this defines how many nanoseconds do we pretend
10-
/// are passing for each basic block.
11-
const NANOSECOND_PER_BASIC_BLOCK: u64 = 10;
12-
13-
#[derive(Debug)]
14-
pub struct Instant {
15-
kind: InstantKind,
16-
}
17-
18-
#[derive(Debug)]
19-
enum InstantKind {
20-
Host(StdInstant),
21-
Virtual { nanoseconds: u64 },
22-
}
23-
24-
/// A monotone clock used for `Instant` simulation.
25-
#[derive(Debug)]
26-
pub struct Clock {
27-
kind: ClockKind,
28-
}
29-
30-
#[derive(Debug)]
31-
enum ClockKind {
32-
Host {
33-
/// The "time anchor" for this machine's monotone clock.
34-
time_anchor: StdInstant,
35-
},
36-
Virtual {
37-
/// The "current virtual time".
38-
nanoseconds: AtomicU64,
39-
},
40-
}
41-
42-
impl Clock {
43-
/// Create a new clock based on the availability of communication with the host.
44-
pub fn new(communicate: bool) -> Self {
45-
let kind = if communicate {
46-
ClockKind::Host { time_anchor: StdInstant::now() }
47-
} else {
48-
ClockKind::Virtual { nanoseconds: 0.into() }
49-
};
50-
51-
Self { kind }
52-
}
53-
54-
/// Get the current time relative to this clock.
55-
pub fn get(&self) -> Duration {
56-
match &self.kind {
57-
ClockKind::Host { time_anchor } =>
58-
StdInstant::now().saturating_duration_since(*time_anchor),
59-
ClockKind::Virtual { nanoseconds } =>
60-
Duration::from_nanos(nanoseconds.load(Ordering::Relaxed)),
61-
}
62-
}
63-
64-
/// Let the time pass for a small interval.
65-
pub fn tick(&self) {
66-
match &self.kind {
67-
ClockKind::Host { .. } => {
68-
// Time will pass without us doing anything.
69-
}
70-
ClockKind::Virtual { nanoseconds } => {
71-
nanoseconds.fetch_add(NANOSECOND_PER_BASIC_BLOCK, Ordering::Relaxed);
72-
}
73-
}
74-
}
75-
76-
/// Sleep for the desired duration.
77-
pub fn sleep(&self, duration: Duration) {
78-
match &self.kind {
79-
ClockKind::Host { .. } => std::thread::sleep(duration),
80-
ClockKind::Virtual { nanoseconds } => {
81-
// Just pretend that we have slept for some time.
82-
nanoseconds.fetch_add(duration.as_nanos().try_into().unwrap(), Ordering::Relaxed);
83-
}
84-
}
85-
}
86-
87-
/// Compute `now + duration` relative to this clock.
88-
pub fn get_time_relative(&self, duration: Duration) -> Option<Time> {
89-
match &self.kind {
90-
ClockKind::Host { .. } =>
91-
StdInstant::now()
92-
.checked_add(duration)
93-
.map(|instant| Time::Monotonic(Instant { kind: InstantKind::Host(instant) })),
94-
ClockKind::Virtual { nanoseconds } =>
95-
nanoseconds
96-
.load(Ordering::Relaxed)
97-
.checked_add(duration.as_nanos().try_into().unwrap())
98-
.map(|nanoseconds| {
99-
Time::Monotonic(Instant { kind: InstantKind::Virtual { nanoseconds } })
100-
}),
101-
}
102-
}
103-
104-
/// Compute `start + duration` relative to this clock where `start` is the instant of time when
105-
/// this clock was created.
106-
pub fn get_time_absolute(&self, duration: Duration) -> Option<Time> {
107-
match &self.kind {
108-
ClockKind::Host { time_anchor } =>
109-
time_anchor
110-
.checked_add(duration)
111-
.map(|instant| Time::Monotonic(Instant { kind: InstantKind::Host(instant) })),
112-
ClockKind::Virtual { .. } =>
113-
Some(Time::Monotonic(Instant {
114-
kind: InstantKind::Virtual {
115-
nanoseconds: duration.as_nanos().try_into().unwrap(),
116-
},
117-
})),
118-
}
119-
}
120-
121-
/// How long do we have to wait from now until the specified time?
122-
pub fn get_wait_time(&self, time: &Time) -> Duration {
123-
match time {
124-
Time::Monotonic(instant) =>
125-
match (&instant.kind, &self.kind) {
126-
(InstantKind::Host(instant), ClockKind::Host { .. }) =>
127-
instant.saturating_duration_since(StdInstant::now()),
128-
(
129-
InstantKind::Virtual { nanoseconds },
130-
ClockKind::Virtual { nanoseconds: current_ns },
131-
) =>
132-
Duration::from_nanos(
133-
nanoseconds.saturating_sub(current_ns.load(Ordering::Relaxed)),
134-
),
135-
_ => panic!(),
136-
},
137-
Time::RealTime(time) =>
138-
time.duration_since(SystemTime::now()).unwrap_or(Duration::new(0, 0)),
139-
}
140-
}
141-
}
142-
1435
/// Returns the time elapsed between the provided time and the unix epoch as a `Duration`.
1446
pub fn system_time_to_duration<'tcx>(time: &SystemTime) -> InterpResult<'tcx, Duration> {
1457
time.duration_since(SystemTime::UNIX_EPOCH)
@@ -354,7 +216,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
354216

355217
this.register_timeout_callback(
356218
active_thread,
357-
timeout_time,
219+
Time::Monotonic(timeout_time),
358220
Box::new(move |ecx| {
359221
ecx.unblock_thread(active_thread);
360222
Ok(())
@@ -380,7 +242,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
380242

381243
this.register_timeout_callback(
382244
active_thread,
383-
timeout_time,
245+
Time::Monotonic(timeout_time),
384246
Box::new(move |ecx| {
385247
ecx.unblock_thread(active_thread);
386248
Ok(())

src/shims/unix/linux/sync.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,14 +106,14 @@ pub fn futex<'tcx>(
106106
if op & futex_realtime != 0 {
107107
Time::RealTime(SystemTime::UNIX_EPOCH.checked_add(duration).unwrap())
108108
} else {
109-
this.machine.clock.get_time_absolute(duration).unwrap()
109+
Time::Monotonic(this.machine.clock.get_time_absolute(duration).unwrap())
110110
}
111111
} else {
112112
// FUTEX_WAIT uses a relative timestamp.
113113
if op & futex_realtime != 0 {
114114
Time::RealTime(SystemTime::now().checked_add(duration).unwrap())
115115
} else {
116-
this.machine.clock.get_time_relative(duration).unwrap()
116+
Time::Monotonic(this.machine.clock.get_time_relative(duration).unwrap())
117117
}
118118
})
119119
};

0 commit comments

Comments
 (0)