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 ) -> InterpResult<'tcx, Scalar> {
45 let this = self.eval_context_mut();
46
47 if !this.ptr_is_null(this.read_pointer(retval)?)? {
48 throw_unsup_format!("Miri supports pthread_join only with retval==NULL");
50 }
51
52 let thread = this.read_scalar(thread)?.to_int(this.libc_ty_layout("pthread_t").size)?;
53 let Ok(thread) = this.thread_id_try_from(thread) else {
54 return interp_ok(this.eval_libc("ESRCH"));
55 };
56
57 this.join_thread_exclusive(thread)?;
58
59 interp_ok(Scalar::from_u32(0))
60 }
61
62 fn pthread_detach(&mut self, thread: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
63 let this = self.eval_context_mut();
64
65 let thread = this.read_scalar(thread)?.to_int(this.libc_ty_layout("pthread_t").size)?;
66 let Ok(thread) = this.thread_id_try_from(thread) else {
67 return interp_ok(this.eval_libc("ESRCH"));
68 };
69 this.detach_thread(thread, false)?;
70
71 interp_ok(Scalar::from_u32(0))
72 }
73
74 fn pthread_self(&mut self) -> InterpResult<'tcx, Scalar> {
75 let this = self.eval_context_mut();
76
77 let thread_id = this.active_thread();
78 interp_ok(Scalar::from_uint(thread_id.to_u32(), this.libc_ty_layout("pthread_t").size))
79 }
80
81 fn pthread_setname_np(
86 &mut self,
87 thread: Scalar,
88 name: Scalar,
89 name_max_len: usize,
90 truncate: bool,
91 ) -> InterpResult<'tcx, ThreadNameResult> {
92 let this = self.eval_context_mut();
93
94 let thread = thread.to_int(this.libc_ty_layout("pthread_t").size)?;
95 let Ok(thread) = this.thread_id_try_from(thread) else {
96 return interp_ok(ThreadNameResult::ThreadNotFound);
97 };
98 let name = name.to_pointer(this)?;
99 let mut name = this.read_c_str(name)?.to_owned();
100
101 if name.len() >= name_max_len {
103 if truncate {
104 name.truncate(name_max_len.saturating_sub(1));
105 } else {
106 return interp_ok(ThreadNameResult::NameTooLong);
107 }
108 }
109
110 this.set_thread_name(thread, name);
111
112 interp_ok(ThreadNameResult::Ok)
113 }
114
115 fn pthread_getname_np(
120 &mut self,
121 thread: Scalar,
122 name_out: Scalar,
123 len: Scalar,
124 truncate: bool,
125 ) -> InterpResult<'tcx, ThreadNameResult> {
126 let this = self.eval_context_mut();
127
128 let thread = thread.to_int(this.libc_ty_layout("pthread_t").size)?;
129 let Ok(thread) = this.thread_id_try_from(thread) else {
130 return interp_ok(ThreadNameResult::ThreadNotFound);
131 };
132 let name_out = name_out.to_pointer(this)?;
133 let len = len.to_target_usize(this)?;
134
135 let name = this.get_thread_name(thread).unwrap_or(b"<unnamed>").to_owned();
137 let name = match truncate {
138 true => &name[..name.len().min(len.try_into().unwrap_or(usize::MAX).saturating_sub(1))],
139 false => &name,
140 };
141
142 let (success, _written) = this.write_c_str(name, name_out, len)?;
143 let res = if success { ThreadNameResult::Ok } else { ThreadNameResult::NameTooLong };
144
145 interp_ok(res)
146 }
147
148 fn sched_yield(&mut self) -> InterpResult<'tcx, ()> {
149 let this = self.eval_context_mut();
150
151 this.yield_active_thread();
152
153 interp_ok(())
154 }
155}