miri/shims/unix/
thread.rs1use rustc_abi::ExternAbi;
2
3use crate::*;
4
5#[derive(Debug, Clone, PartialEq, Eq)]
6pub enum ThreadNameResult {
7 Ok,
8 NameTooLong,
9 ThreadNotFound,
10}
11
12impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
13pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
14 fn pthread_create(
15 &mut self,
16 thread: &OpTy<'tcx>,
17 _attr: &OpTy<'tcx>,
18 start_routine: &OpTy<'tcx>,
19 arg: &OpTy<'tcx>,
20 ) -> InterpResult<'tcx, ()> {
21 let this = self.eval_context_mut();
22
23 let thread_info_place = this.deref_pointer_as(thread, this.libc_ty_layout("pthread_t"))?;
24
25 let start_routine = this.read_pointer(start_routine)?;
26
27 let func_arg = this.read_immediate(arg)?;
28
29 this.start_regular_thread(
30 Some(thread_info_place),
31 start_routine,
32 ExternAbi::C { unwind: false },
33 func_arg,
34 this.machine.layouts.mut_raw_ptr,
35 )?;
36
37 interp_ok(())
38 }
39
40 fn pthread_join(
41 &mut self,
42 thread: &OpTy<'tcx>,
43 retval: &OpTy<'tcx>,
44 return_dest: &MPlaceTy<'tcx>,
45 ) -> InterpResult<'tcx> {
46 let this = self.eval_context_mut();
47
48 if !this.ptr_is_null(this.read_pointer(retval)?)? {
49 throw_unsup_format!("Miri supports pthread_join only with retval==NULL");
51 }
52
53 let thread = this.read_scalar(thread)?.to_int(this.libc_ty_layout("pthread_t").size)?;
54 let Ok(thread) = this.thread_id_try_from(thread) else {
55 this.write_scalar(this.eval_libc("ESRCH"), return_dest)?;
56 return interp_ok(());
57 };
58
59 this.join_thread_exclusive(
60 thread,
61 Scalar::from_u32(0),
62 return_dest,
63 )
64 }
65
66 fn pthread_detach(&mut self, thread: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
67 let this = self.eval_context_mut();
68
69 let thread = this.read_scalar(thread)?.to_int(this.libc_ty_layout("pthread_t").size)?;
70 let Ok(thread) = this.thread_id_try_from(thread) else {
71 return interp_ok(this.eval_libc("ESRCH"));
72 };
73 this.detach_thread(thread, false)?;
74
75 interp_ok(Scalar::from_u32(0))
76 }
77
78 fn pthread_self(&mut self) -> InterpResult<'tcx, Scalar> {
79 let this = self.eval_context_mut();
80
81 let thread_id = this.active_thread();
82 interp_ok(Scalar::from_uint(thread_id.to_u32(), this.libc_ty_layout("pthread_t").size))
83 }
84
85 fn pthread_setname_np(
90 &mut self,
91 thread: Scalar,
92 name: Scalar,
93 name_max_len: u64,
94 truncate: bool,
95 ) -> InterpResult<'tcx, ThreadNameResult> {
96 let this = self.eval_context_mut();
97
98 let thread = thread.to_int(this.libc_ty_layout("pthread_t").size)?;
99 let Ok(thread) = this.thread_id_try_from(thread) else {
100 return interp_ok(ThreadNameResult::ThreadNotFound);
101 };
102 let name = name.to_pointer(this)?;
103 let mut name = this.read_c_str(name)?.to_owned();
104
105 if name.len().to_u64() >= name_max_len {
107 if truncate {
108 name.truncate(name_max_len.saturating_sub(1).try_into().unwrap());
109 } else {
110 return interp_ok(ThreadNameResult::NameTooLong);
111 }
112 }
113
114 this.set_thread_name(thread, name);
115
116 interp_ok(ThreadNameResult::Ok)
117 }
118
119 fn pthread_getname_np(
124 &mut self,
125 thread: Scalar,
126 name_out: Scalar,
127 len: Scalar,
128 truncate: bool,
129 ) -> InterpResult<'tcx, ThreadNameResult> {
130 let this = self.eval_context_mut();
131
132 let thread = thread.to_int(this.libc_ty_layout("pthread_t").size)?;
133 let Ok(thread) = this.thread_id_try_from(thread) else {
134 return interp_ok(ThreadNameResult::ThreadNotFound);
135 };
136 let name_out = name_out.to_pointer(this)?;
137 let len = len.to_target_usize(this)?;
138
139 let name = this.get_thread_name(thread).unwrap_or(b"<unnamed>").to_owned();
141 let name = match truncate {
142 true => &name[..name.len().min(len.try_into().unwrap_or(usize::MAX).saturating_sub(1))],
143 false => &name,
144 };
145
146 let (success, _written) = this.write_c_str(name, name_out, len)?;
147 let res = if success { ThreadNameResult::Ok } else { ThreadNameResult::NameTooLong };
148
149 interp_ok(res)
150 }
151
152 fn sched_yield(&mut self) -> InterpResult<'tcx, ()> {
153 let this = self.eval_context_mut();
154
155 this.yield_active_thread();
156
157 interp_ok(())
158 }
159}