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