Implement thread::yield_now.

This commit is contained in:
Vytautas Astrauskas 2020-04-18 15:39:53 -07:00
parent 134533d066
commit 46fd333daa
3 changed files with 40 additions and 5 deletions

View File

@ -318,6 +318,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
let result = this.prctl(args[0], args[1], args[2], args[3], args[4])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"sched_yield" => {
assert_eq!(args.len(), 0);
let result = this.sched_yield()?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
// Miscellaneous
"isatty" => {

View File

@ -111,4 +111,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
Ok(0)
}
fn sched_yield(&mut self) -> InterpResult<'tcx, i32> {
let this = self.eval_context_mut();
this.yield_active_thread()?;
Ok(0)
}
}

View File

@ -143,6 +143,8 @@ pub struct ThreadManager<'mir, 'tcx> {
/// A mapping from a thread-local static to an allocation id of a thread
/// specific allocation.
thread_local_alloc_ids: RefCell<FxHashMap<(DefId, ThreadId), AllocId>>,
/// A flag that indicates that we should change the active thread.
yield_active_thread: bool,
}
impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> {
@ -154,6 +156,7 @@ impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> {
threads: threads,
blockset_counter: 0,
thread_local_alloc_ids: Default::default(),
yield_active_thread: false,
}
}
}
@ -275,6 +278,11 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
None
}
/// Change the active thread to some enabled thread.
fn yield_active_thread(&mut self) {
self.yield_active_thread = true;
}
/// Decide which action to take next and on which thread.
fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> {
if self.threads[self.active_thread].check_terminated() {
@ -287,13 +295,21 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
}
return Ok(SchedulingAction::ExecuteDtors);
}
if self.threads[self.active_thread].state == ThreadState::Enabled {
if self.threads[self.active_thread].state == ThreadState::Enabled
&& !self.yield_active_thread
{
return Ok(SchedulingAction::ExecuteStep);
}
if let Some(enabled_thread) =
self.threads.iter().position(|thread| thread.state == ThreadState::Enabled)
{
self.active_thread = ThreadId::new(enabled_thread);
for (id, thread) in self.threads.iter_enumerated() {
if thread.state == ThreadState::Enabled {
if !(self.yield_active_thread && id == self.active_thread) {
self.active_thread = id;
break;
}
}
}
self.yield_active_thread = false;
if self.threads[self.active_thread].state == ThreadState::Enabled {
return Ok(SchedulingAction::ExecuteStep);
}
if self.threads.iter().all(|thread| thread.state == ThreadState::Terminated) {
@ -453,6 +469,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
Ok(this.machine.threads.unblock_random_thread(set))
}
fn yield_active_thread(&mut self) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
this.machine.threads.yield_active_thread();
Ok(())
}
/// Decide which action to take next and on which thread.
fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> {
let this = self.eval_context_mut();