]> git.lizzy.rs Git - rust.git/blob - src/tools/miri/src/shims/unix/thread.rs
5b9dc90f0f0060c63524e4297e83aec4d8301532
[rust.git] / src / tools / miri / src / shims / unix / thread.rs
1 use crate::*;
2 use rustc_middle::ty::layout::LayoutOf;
3 use rustc_target::spec::abi::Abi;
4
5 impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
6 pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
7     fn pthread_create(
8         &mut self,
9         thread: &OpTy<'tcx, Provenance>,
10         _attr: &OpTy<'tcx, Provenance>,
11         start_routine: &OpTy<'tcx, Provenance>,
12         arg: &OpTy<'tcx, Provenance>,
13     ) -> InterpResult<'tcx, i32> {
14         let this = self.eval_context_mut();
15
16         let thread_info_place = this.deref_operand(thread)?;
17
18         let start_routine = this.read_pointer(start_routine)?;
19
20         let func_arg = this.read_immediate(arg)?;
21
22         this.start_regular_thread(
23             Some(thread_info_place),
24             start_routine,
25             Abi::C { unwind: false },
26             func_arg,
27             this.layout_of(this.tcx.types.usize)?,
28         )?;
29
30         Ok(0)
31     }
32
33     fn pthread_join(
34         &mut self,
35         thread: &OpTy<'tcx, Provenance>,
36         retval: &OpTy<'tcx, Provenance>,
37     ) -> InterpResult<'tcx, i32> {
38         let this = self.eval_context_mut();
39
40         if !this.ptr_is_null(this.read_pointer(retval)?)? {
41             // FIXME: implement reading the thread function's return place.
42             throw_unsup_format!("Miri supports pthread_join only with retval==NULL");
43         }
44
45         let thread_id = this.read_scalar(thread)?.to_machine_usize(this)?;
46         this.join_thread_exclusive(thread_id.try_into().expect("thread ID should fit in u32"))?;
47
48         Ok(0)
49     }
50
51     fn pthread_detach(&mut self, thread: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> {
52         let this = self.eval_context_mut();
53
54         let thread_id = this.read_scalar(thread)?.to_machine_usize(this)?;
55         this.detach_thread(
56             thread_id.try_into().expect("thread ID should fit in u32"),
57             /*allow_terminated_joined*/ false,
58         )?;
59
60         Ok(0)
61     }
62
63     fn pthread_self(&mut self) -> InterpResult<'tcx, Scalar<Provenance>> {
64         let this = self.eval_context_mut();
65
66         let thread_id = this.get_active_thread();
67         Ok(Scalar::from_machine_usize(thread_id.into(), this))
68     }
69
70     /// Set the name of the current thread. `max_name_len` is the maximal length of the name
71     /// including the null terminator.
72     fn pthread_setname_np(
73         &mut self,
74         thread: Scalar<Provenance>,
75         name: Scalar<Provenance>,
76         max_name_len: usize,
77     ) -> InterpResult<'tcx, Scalar<Provenance>> {
78         let this = self.eval_context_mut();
79
80         let thread = ThreadId::try_from(thread.to_machine_usize(this)?).unwrap();
81         let name = name.to_pointer(this)?;
82
83         let name = this.read_c_str(name)?.to_owned();
84
85         // Comparing with `>=` to account for null terminator.
86         if name.len() >= max_name_len {
87             return this.eval_libc("ERANGE");
88         }
89
90         this.set_thread_name(thread, name);
91
92         Ok(Scalar::from_u32(0))
93     }
94
95     fn pthread_getname_np(
96         &mut self,
97         thread: Scalar<Provenance>,
98         name_out: Scalar<Provenance>,
99         len: Scalar<Provenance>,
100     ) -> InterpResult<'tcx, Scalar<Provenance>> {
101         let this = self.eval_context_mut();
102
103         let thread = ThreadId::try_from(thread.to_machine_usize(this)?).unwrap();
104         let name_out = name_out.to_pointer(this)?;
105         let len = len.to_machine_usize(this)?;
106
107         let name = this.get_thread_name(thread).to_owned();
108         let (success, _written) = this.write_c_str(&name, name_out, len)?;
109
110         if success { Ok(Scalar::from_u32(0)) } else { this.eval_libc("ERANGE") }
111     }
112
113     fn sched_yield(&mut self) -> InterpResult<'tcx, i32> {
114         let this = self.eval_context_mut();
115
116         this.yield_active_thread();
117
118         Ok(0)
119     }
120 }