Move pthread_create and related shims to a separate file.

This commit is contained in:
Vytautas Astrauskas 2020-04-06 13:44:47 -07:00
parent aef4c95599
commit 1f33f04fd4
5 changed files with 93 additions and 59 deletions

View File

@ -42,6 +42,7 @@ pub use crate::shims::intrinsics::EvalContextExt as IntrinsicsEvalContextExt;
pub use crate::shims::os_str::EvalContextExt as OsStrEvalContextExt;
pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as PanicEvalContextExt};
pub use crate::shims::sync::{EvalContextExt as SyncEvalContextExt};
pub use crate::shims::threads::EvalContextExt as ThreadShimsEvalContextExt;
pub use crate::shims::time::EvalContextExt as TimeEvalContextExt;
pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData};
pub use crate::shims::EvalContextExt as ShimsEvalContextExt;

View File

@ -6,7 +6,6 @@ use std::convert::TryFrom;
use log::trace;
use crate::*;
use rustc_index::vec::Idx;
use rustc_middle::mir;
use rustc_target::abi::{Align, LayoutOf, Size};
@ -316,66 +315,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
// Threading
"pthread_create" => {
println!("WARNING: The thread support is experimental. \
For example, Miri does not detect data races yet.");
assert_eq!(args.len(), 4);
let func = args[2];
let fn_ptr = this.read_scalar(func)?.not_undef()?;
let fn_val = this.memory.get_fn(fn_ptr)?;
let instance = match fn_val {
rustc_mir::interpret::FnVal::Instance(instance) => instance,
_ => unreachable!(),
};
let thread_info_place = this.deref_operand(args[0])?;
let thread_info_type = args[0].layout.ty
.builtin_deref(true)
.ok_or_else(|| err_ub_format!(
"wrong signature used for `pthread_create`: first argument must be a raw pointer."
))?
.ty;
let thread_info_layout = this.layout_of(thread_info_type)?;
let func_arg = match *args[3] {
rustc_mir::interpret::Operand::Immediate(immediate) => immediate,
_ => unreachable!(),
};
let func_args = [func_arg];
let ret_place =
this.allocate(this.layout_of(this.tcx.types.usize)?, MiriMemoryKind::Machine.into());
let new_thread_id = this.create_thread()?;
let old_thread_id = this.set_active_thread(new_thread_id)?;
this.call_function(
instance,
&func_args[..],
Some(ret_place.into()),
StackPopCleanup::None { cleanup: true },
)?;
this.set_active_thread(old_thread_id)?;
this.write_scalar(
Scalar::from_uint(new_thread_id.index() as u128, thread_info_layout.size),
thread_info_place.into(),
)?;
// Return success (`0`).
this.write_null(dest)?;
let result = this.pthread_create(args[0], args[1], args[2], args[3])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"pthread_join" => {
assert_eq!(args.len(), 2);
assert!(
this.is_null(this.read_scalar(args[1])?.not_undef()?)?,
"Miri supports pthread_join only with retval==NULL"
);
let thread = this.read_scalar(args[0])?.not_undef()?.to_machine_usize(this)?;
this.join_thread(thread.into())?;
// Return success (`0`).
this.write_null(dest)?;
let result = this.pthread_join(args[0], args[1])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"pthread_detach" => {
let thread = this.read_scalar(args[0])?.not_undef()?.to_machine_usize(this)?;
this.detach_thread(thread.into())?;
// Return success (`0`).
this.write_null(dest)?;
assert_eq!(args.len(), 1);
let result = this.pthread_detach(args[0])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"pthread_attr_getguardsize" => {

View File

@ -6,6 +6,7 @@ pub mod intrinsics;
pub mod os_str;
pub mod panic;
pub mod sync;
pub mod threads;
pub mod time;
pub mod tls;

84
src/shims/threads.rs Normal file
View File

@ -0,0 +1,84 @@
use crate::*;
use rustc_index::vec::Idx;
use rustc_target::abi::LayoutOf;
impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
fn pthread_create(
&mut self,
thread: OpTy<'tcx, Tag>,
_attr: OpTy<'tcx, Tag>,
start_routine: OpTy<'tcx, Tag>,
arg: OpTy<'tcx, Tag>,
) -> InterpResult<'tcx, i32> {
println!(
"WARNING: The thread support is experimental. \
For example, Miri does not detect data races yet."
);
let this = self.eval_context_mut();
let new_thread_id = this.create_thread()?;
let old_thread_id = this.set_active_thread(new_thread_id)?;
let thread_info_place = this.deref_operand(thread)?;
let thread_info_type = thread.layout.ty
.builtin_deref(true)
.ok_or_else(|| err_ub_format!(
"wrong signature used for `pthread_create`: first argument must be a raw pointer."
))?
.ty;
let thread_info_layout = this.layout_of(thread_info_type)?;
this.write_scalar(
Scalar::from_uint(new_thread_id.index() as u128, thread_info_layout.size),
thread_info_place.into(),
)?;
let fn_ptr = this.read_scalar(start_routine)?.not_undef()?;
let instance = this.memory.get_fn(fn_ptr)?.as_instance()?;
let func_arg = match *arg {
rustc_mir::interpret::Operand::Immediate(immediate) => immediate,
_ => unreachable!(),
};
let func_args = [func_arg];
let ret_place =
this.allocate(this.layout_of(this.tcx.types.usize)?, MiriMemoryKind::Machine.into());
this.call_function(
instance,
&func_args[..],
Some(ret_place.into()),
StackPopCleanup::None { cleanup: true },
)?;
this.set_active_thread(old_thread_id)?;
Ok(0)
}
fn pthread_join(
&mut self,
thread: OpTy<'tcx, Tag>,
retval: OpTy<'tcx, Tag>,
) -> InterpResult<'tcx, i32> {
let this = self.eval_context_mut();
if !this.is_null(this.read_scalar(retval)?.not_undef()?)? {
throw_unsup_format!("Miri supports pthread_join only with retval==NULL");
}
let thread_id = this.read_scalar(thread)?.not_undef()?.to_machine_usize(this)?;
this.join_thread(thread_id.into())?;
Ok(0)
}
fn pthread_detach(&mut self, thread: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
let this = self.eval_context_mut();
let thread_id = this.read_scalar(thread)?.not_undef()?.to_machine_usize(this)?;
this.detach_thread(thread_id.into())?;
Ok(0)
}
}

View File

@ -91,9 +91,6 @@ pub struct ThreadSet<'mir, 'tcx> {
///
/// Note that this vector also contains terminated threads.
threads: IndexVec<ThreadId, Thread<'mir, 'tcx>>,
/// List of threads that just terminated. TODO: Cleanup.
terminated_threads: Vec<ThreadId>,
}
impl<'mir, 'tcx> Default for ThreadSet<'mir, 'tcx> {
@ -103,7 +100,6 @@ impl<'mir, 'tcx> Default for ThreadSet<'mir, 'tcx> {
Self {
active_thread: ThreadId::new(0),
threads: threads,
terminated_threads: Default::default(),
}
}
}