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