Skip to content

Commit 0bbac12

Browse files
committed
Change how the time is handled.
1 parent 86eb262 commit 0bbac12

File tree

4 files changed

+36
-34
lines changed

4 files changed

+36
-34
lines changed

src/machine.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::borrow::Cow;
55
use std::cell::RefCell;
66
use std::num::NonZeroU64;
77
use std::rc::Rc;
8-
use std::time::{Instant, SystemTime};
8+
use std::time::Instant;
99
use std::fmt;
1010

1111
use log::trace;
@@ -251,11 +251,6 @@ pub struct Evaluator<'mir, 'tcx> {
251251
/// The "time anchor" for this machine's monotone clock (for `Instant` simulation).
252252
pub(crate) time_anchor: Instant,
253253

254-
/// The approximate system time when "time anchor" was created. This is used
255-
/// for converting system time to monotone time so that we can simplify the
256-
/// thread scheduler to deal only with a single representation of time.
257-
pub(crate) time_anchor_timestamp: SystemTime,
258-
259254
/// The set of threads.
260255
pub(crate) threads: ThreadManager<'mir, 'tcx>,
261256

@@ -286,7 +281,6 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> {
286281
dir_handler: Default::default(),
287282
panic_payload: None,
288283
time_anchor: Instant::now(),
289-
time_anchor_timestamp: SystemTime::now(),
290284
layouts,
291285
threads: ThreadManager::default(),
292286
}

src/shims/sync.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
use std::time::{Duration, SystemTime};
21
use std::convert::TryInto;
2+
use std::time::{Duration, SystemTime};
33

44
use rustc_middle::ty::{layout::TyAndLayout, TyKind, TypeAndMut};
55
use rustc_target::abi::{LayoutOf, Size};
66

77
use crate::stacked_borrows::Tag;
8+
use crate::thread::Time;
89

910
use crate::*;
1011

@@ -734,12 +735,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
734735
};
735736

736737
let timeout_time = if clock_id == this.eval_libc_i32("CLOCK_REALTIME")? {
737-
let time_anchor_since_epoch =
738-
this.machine.time_anchor_timestamp.duration_since(SystemTime::UNIX_EPOCH).unwrap();
739-
let duration_since_time_anchor = duration.checked_sub(time_anchor_since_epoch).unwrap();
740-
this.machine.time_anchor.checked_add(duration_since_time_anchor).unwrap()
738+
Time::RealTime(SystemTime::UNIX_EPOCH.checked_add(duration).unwrap())
741739
} else if clock_id == this.eval_libc_i32("CLOCK_MONOTONIC")? {
742-
this.machine.time_anchor.checked_add(duration).unwrap()
740+
Time::Monotonic(this.machine.time_anchor.checked_add(duration).unwrap())
743741
} else {
744742
throw_ub_format!("Unsupported clock id.");
745743
};

src/sync.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use std::collections::{hash_map::Entry, HashMap, VecDeque};
22
use std::convert::TryFrom;
33
use std::num::NonZeroU32;
4-
use std::time::Instant;
54

65
use rustc_index::vec::{Idx, IndexVec};
76

@@ -76,8 +75,6 @@ struct CondvarWaiter {
7675
thread: ThreadId,
7776
/// The mutex on which the thread is waiting.
7877
mutex: MutexId,
79-
/// The moment in time when the waiter should time out.
80-
timeout: Option<Instant>,
8178
}
8279

8380
/// The conditional variable state.
@@ -280,7 +277,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
280277
let this = self.eval_context_mut();
281278
let waiters = &mut this.machine.threads.sync.condvars[id].waiters;
282279
assert!(waiters.iter().all(|waiter| waiter.thread != thread), "thread is already waiting");
283-
waiters.push_back(CondvarWaiter { thread, mutex, timeout: None });
280+
waiters.push_back(CondvarWaiter { thread, mutex });
284281
}
285282

286283
/// Wake up some thread (if there is any) sleeping on the conditional

src/thread.rs

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::cell::RefCell;
44
use std::collections::hash_map::Entry;
55
use std::convert::TryFrom;
66
use std::num::TryFromIntError;
7-
use std::time::Instant;
7+
use std::time::{Duration, Instant, SystemTime};
88

99
use log::trace;
1010

@@ -159,13 +159,30 @@ impl<'mir, 'tcx> Default for Thread<'mir, 'tcx> {
159159
}
160160
}
161161

162+
#[derive(Debug)]
163+
pub enum Time {
164+
Monotonic(Instant),
165+
RealTime(SystemTime),
166+
}
167+
168+
impl Time {
169+
/// How long do we have to wait from now until the specified time?
170+
fn get_wait_time(&self) -> Duration {
171+
match self {
172+
Time::Monotonic(instant) => instant.saturating_duration_since(Instant::now()),
173+
Time::RealTime(time) =>
174+
time.duration_since(SystemTime::now()).unwrap_or(Duration::new(0, 0)),
175+
}
176+
}
177+
}
178+
162179
/// Callbacks are used to implement timeouts. For example, waiting on a
163180
/// conditional variable with a timeout creates a callback that is called after
164181
/// the specified time and unblocks the thread. If another thread signals on the
165182
/// conditional variable, the signal handler deletes the callback.
166183
struct TimeoutCallbackInfo<'mir, 'tcx> {
167184
/// The callback should be called no earlier than this time.
168-
call_time: Instant,
185+
call_time: Time,
169186
/// The called function.
170187
callback: TimeoutCallback<'mir, 'tcx>,
171188
}
@@ -362,11 +379,11 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
362379
fn register_timeout_callback(
363380
&mut self,
364381
thread: ThreadId,
365-
call_time: Instant,
382+
call_time: Time,
366383
callback: TimeoutCallback<'mir, 'tcx>,
367384
) {
368385
self.timeout_callbacks
369-
.insert(thread, TimeoutCallbackInfo { call_time: call_time, callback: callback })
386+
.insert(thread, TimeoutCallbackInfo { call_time, callback })
370387
.unwrap_none();
371388
}
372389

@@ -376,13 +393,12 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
376393
}
377394

378395
/// Get a callback that is ready to be called.
379-
fn get_callback(&mut self) -> Option<(ThreadId, TimeoutCallback<'mir, 'tcx>)> {
380-
let current_time = Instant::now();
396+
fn get_ready_callback(&mut self) -> Option<(ThreadId, TimeoutCallback<'mir, 'tcx>)> {
381397
// We use a for loop here to make the scheduler more deterministic.
382398
for thread in self.threads.indices() {
383399
match self.timeout_callbacks.entry(thread) {
384400
Entry::Occupied(entry) =>
385-
if current_time >= entry.get().call_time {
401+
if entry.get().call_time.get_wait_time() == Duration::new(0, 0) {
386402
return Some((thread, entry.remove().callback));
387403
},
388404
Entry::Vacant(_) => {}
@@ -445,18 +461,14 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
445461
}
446462
// We have not found a thread to execute.
447463
if self.threads.iter().all(|thread| thread.state == ThreadState::Terminated) {
448-
unreachable!();
449-
} else if let Some(next_call_time) =
450-
self.timeout_callbacks.values().min_by_key(|info| info.call_time)
464+
unreachable!("all threads terminated without the main thread terminating?!");
465+
} else if let Some(sleep_time) =
466+
self.timeout_callbacks.values().map(|info| info.call_time.get_wait_time()).min()
451467
{
452468
// All threads are currently blocked, but we have unexecuted
453469
// timeout_callbacks, which may unblock some of the threads. Hence,
454470
// sleep until the first callback.
455-
if let Some(sleep_time) =
456-
next_call_time.call_time.checked_duration_since(Instant::now())
457-
{
458-
std::thread::sleep(sleep_time);
459-
}
471+
std::thread::sleep(sleep_time);
460472
Ok(SchedulingAction::ExecuteTimeoutCallback)
461473
} else {
462474
throw_machine_stop!(TerminationInfo::Deadlock);
@@ -650,7 +662,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
650662
fn register_timeout_callback(
651663
&mut self,
652664
thread: ThreadId,
653-
call_time: Instant,
665+
call_time: Time,
654666
callback: TimeoutCallback<'mir, 'tcx>,
655667
) -> InterpResult<'tcx> {
656668
let this = self.eval_context_mut();
@@ -669,7 +681,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
669681
#[inline]
670682
fn run_timeout_callback(&mut self) -> InterpResult<'tcx> {
671683
let this = self.eval_context_mut();
672-
let (thread, callback) = this.machine.threads.get_callback().expect("no callback found");
684+
let (thread, callback) =
685+
this.machine.threads.get_ready_callback().expect("no callback found");
673686
let old_thread = this.set_active_thread(thread)?;
674687
callback(this)?;
675688
this.set_active_thread(old_thread)?;

0 commit comments

Comments
 (0)