2 use rustc_middle::ty::layout::LayoutOf;
3 use rustc_target::spec::abi::Abi;
5 impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
6 pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
9 thread: &OpTy<'tcx, Tag>,
10 _attr: &OpTy<'tcx, Tag>,
11 start_routine: &OpTy<'tcx, Tag>,
12 arg: &OpTy<'tcx, Tag>,
13 ) -> InterpResult<'tcx, i32> {
14 let this = self.eval_context_mut();
17 "thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model.",
20 // Create the new thread
21 let new_thread_id = this.create_thread();
23 // Write the current thread-id, switch to the next thread later
24 // to treat this write operation as occuring on the current thread.
25 let thread_info_place = this.deref_operand(thread)?;
27 Scalar::from_uint(new_thread_id.to_u32(), thread_info_place.layout.size),
28 &thread_info_place.into(),
31 // Read the function argument that will be sent to the new thread
32 // before the thread starts executing since reading after the
33 // context switch will incorrectly report a data-race.
34 let fn_ptr = this.read_pointer(start_routine)?;
35 let func_arg = this.read_immediate(arg)?;
37 // Finally switch to new thread so that we can push the first stackframe.
38 // After this all accesses will be treated as occuring in the new thread.
39 let old_thread_id = this.set_active_thread(new_thread_id);
41 // Perform the function pointer load in the new thread frame.
42 let instance = this.get_ptr_fn(fn_ptr)?.as_instance()?;
44 // Note: the returned value is currently ignored (see the FIXME in
45 // pthread_join below) because the Rust standard library does not use
48 this.allocate(this.layout_of(this.tcx.types.usize)?, MiriMemoryKind::Machine.into())?;
52 Abi::C { unwind: false },
55 StackPopCleanup::Root { cleanup: true },
58 // Restore the old active thread frame.
59 this.set_active_thread(old_thread_id);
66 thread: &OpTy<'tcx, Tag>,
67 retval: &OpTy<'tcx, Tag>,
68 ) -> InterpResult<'tcx, i32> {
69 let this = self.eval_context_mut();
71 if !this.ptr_is_null(this.read_pointer(retval)?)? {
72 // FIXME: implement reading the thread function's return place.
73 throw_unsup_format!("Miri supports pthread_join only with retval==NULL");
76 let thread_id = this.read_scalar(thread)?.to_machine_usize(this)?;
77 this.join_thread(thread_id.try_into().expect("thread ID should fit in u32"))?;
82 fn pthread_detach(&mut self, thread: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
83 let this = self.eval_context_mut();
85 let thread_id = this.read_scalar(thread)?.to_machine_usize(this)?;
86 this.detach_thread(thread_id.try_into().expect("thread ID should fit in u32"))?;
91 fn pthread_self(&mut self, dest: &PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> {
92 let this = self.eval_context_mut();
94 let thread_id = this.get_active_thread();
95 this.write_scalar(Scalar::from_uint(thread_id.to_u32(), dest.layout.size), dest)
98 fn prctl(&mut self, args: &[OpTy<'tcx, Tag>]) -> InterpResult<'tcx, i32> {
99 let this = self.eval_context_mut();
100 this.assert_target_os("linux", "prctl");
104 "incorrect number of arguments for `prctl`: got {}, expected at least 1",
109 let option = this.read_scalar(&args[0])?.to_i32()?;
110 if option == this.eval_libc_i32("PR_SET_NAME")? {
113 "incorrect number of arguments for `prctl` with `PR_SET_NAME`: got {}, expected at least 2",
118 let address = this.read_pointer(&args[1])?;
119 let mut name = this.read_c_str(address)?.to_owned();
120 // The name should be no more than 16 bytes, including the null
121 // byte. Since `read_c_str` returns the string without the null
122 // byte, we need to truncate to 15.
124 this.set_active_thread_name(name);
125 } else if option == this.eval_libc_i32("PR_GET_NAME")? {
128 "incorrect number of arguments for `prctl` with `PR_SET_NAME`: got {}, expected at least 2",
133 let address = this.read_pointer(&args[1])?;
134 let mut name = this.get_active_thread_name().to_vec();
136 assert!(name.len() <= 16);
137 this.write_bytes_ptr(address, name)?;
139 throw_unsup_format!("unsupported prctl option {}", option);
145 fn pthread_setname_np(&mut self, name: Pointer<Option<Tag>>) -> InterpResult<'tcx> {
146 let this = self.eval_context_mut();
147 this.assert_target_os("macos", "pthread_setname_np");
149 let name = this.read_c_str(name)?.to_owned();
150 this.set_active_thread_name(name);
155 fn sched_yield(&mut self) -> InterpResult<'tcx, i32> {
156 let this = self.eval_context_mut();
158 this.yield_active_thread();