1use crate::{
8 ExceptionReport, MonotonicDuration, NullableHandle, ObjectQuery, Profile, Status, Task, Topic,
9 ok, sys,
10};
11use bitflags::bitflags;
12
13bitflags! {
14 #[repr(transparent)]
16 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
17 pub struct RaiseExceptionOptions: u32 {
18 const TARGET_JOB_DEBUGGER = sys::ZX_EXCEPTION_TARGET_JOB_DEBUGGER;
19 }
20}
21
22#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
26#[repr(transparent)]
27pub struct Thread(NullableHandle);
28impl_handle_based!(Thread);
29
30struct ThreadExceptionReport;
31unsafe impl ObjectQuery for ThreadExceptionReport {
32 const TOPIC: Topic = Topic::THREAD_EXCEPTION_REPORT;
33 type InfoTy = sys::zx_exception_report_t;
34}
35
36impl Thread {
37 pub fn start(
43 &self,
44 thread_entry: usize,
45 stack: usize,
46 arg1: usize,
47 arg2: usize,
48 ) -> Result<(), Status> {
49 let thread_raw = self.raw_handle();
50 let status = unsafe { sys::zx_thread_start(thread_raw, thread_entry, stack, arg1, arg2) };
51 ok(status)
52 }
53
54 pub fn set_profile(&self, profile: &Profile, options: u32) -> Result<(), Status> {
59 let thread_raw = self.raw_handle();
60 let profile_raw = profile.raw_handle();
61 let status = unsafe { sys::zx_object_set_profile(thread_raw, profile_raw, options) };
62 ok(status)
63 }
64
65 pub unsafe fn exit() {
76 unsafe { sys::zx_thread_exit() }
77 }
78
79 pub fn exception_report(&self) -> Result<ExceptionReport, Status> {
83 let raw = self.0.get_info_single::<ThreadExceptionReport>()?;
84
85 Ok(unsafe { ExceptionReport::from_raw(raw) })
87 }
88
89 pub fn info(&self) -> Result<ThreadInfo, Status> {
93 Ok(ThreadInfo::from_raw(self.0.get_info_single::<ThreadInfoQuery>()?))
94 }
95
96 pub fn stats(&self) -> Result<ThreadStats, Status> {
100 Ok(ThreadStats::from_raw(self.0.get_info_single::<ThreadStatsQuery>()?))
101 }
102
103 pub fn read_state_general_regs(&self) -> Result<sys::zx_thread_state_general_regs_t, Status> {
104 let mut state = sys::zx_thread_state_general_regs_t::default();
105 let thread_raw = self.raw_handle();
106 let status = unsafe {
107 sys::zx_thread_read_state(
108 thread_raw,
109 sys::ZX_THREAD_STATE_GENERAL_REGS,
110 std::ptr::from_mut(&mut state).cast::<u8>(),
111 std::mem::size_of_val(&state),
112 )
113 };
114 ok(status).map(|_| state)
115 }
116
117 pub fn write_state_general_regs(
118 &self,
119 state: sys::zx_thread_state_general_regs_t,
120 ) -> Result<(), Status> {
121 let thread_raw = self.raw_handle();
122 let status = unsafe {
123 sys::zx_thread_write_state(
124 thread_raw,
125 sys::ZX_THREAD_STATE_GENERAL_REGS,
126 std::ptr::from_ref(&state).cast::<u8>(),
127 std::mem::size_of_val(&state),
128 )
129 };
130 ok(status)
131 }
132
133 pub fn raise_user_exception(
137 options: RaiseExceptionOptions,
138 synth_code: u32,
139 synth_data: u32,
140 ) -> Result<(), Status> {
141 let arch = unsafe { std::mem::zeroed::<sys::zx_exception_header_arch_t>() };
142 let context = sys::zx_exception_context_t { arch, synth_code, synth_data };
143
144 ok(unsafe { sys::zx_thread_raise_exception(options.bits(), sys::ZX_EXCP_USER, &context) })
146 }
147}
148
149impl Task for Thread {}
150
151struct ThreadStatsQuery;
152unsafe impl ObjectQuery for ThreadStatsQuery {
153 const TOPIC: Topic = Topic::THREAD_STATS;
154 type InfoTy = sys::zx_info_thread_stats_t;
155}
156
157#[cfg(target_arch = "x86_64")]
158unsafe_handle_properties!(object: Thread,
159 props: [
160 {query_ty: REGISTER_GS, tag: RegisterGsTag, prop_ty: usize, set: set_register_gs},
161 {query_ty: REGISTER_FS, tag: RegisterFsTag, prop_ty: usize, set: set_register_fs},
162 ]
163);
164
165#[derive(Default, Debug, Copy, Clone, Eq, PartialEq)]
166pub struct ThreadStats {
167 pub total_runtime: MonotonicDuration,
168 pub last_scheduled_cpu: u32,
169}
170
171impl ThreadStats {
172 fn from_raw(
173 sys::zx_info_thread_stats_t { total_runtime, last_scheduled_cpu }: sys::zx_info_thread_stats_t,
174 ) -> Self {
175 Self { total_runtime: MonotonicDuration::from_nanos(total_runtime), last_scheduled_cpu }
176 }
177}
178
179struct ThreadInfoQuery;
180unsafe impl ObjectQuery for ThreadInfoQuery {
181 const TOPIC: Topic = Topic::THREAD;
182 type InfoTy = sys::zx_info_thread_t;
183}
184
185#[derive(Debug, Copy, Clone, Eq, PartialEq)]
186pub struct ThreadInfo {
187 pub state: ThreadState,
188 pub cpu_affinity_mask: sys::zx_cpu_set_t,
189}
190
191impl ThreadInfo {
192 fn from_raw(raw: sys::zx_info_thread_t) -> Self {
193 Self {
194 state: ThreadState::from_raw(raw.state, raw.wait_exception_channel_type),
195 cpu_affinity_mask: raw.cpu_affinity_mask,
196 }
197 }
198}
199
200#[derive(Debug, Copy, Clone, Eq, PartialEq)]
201pub enum ThreadState {
202 New,
203 Running,
204 Suspended,
205 Blocked(ThreadBlockType),
206 Dying,
207 Dead,
208 Unknown(u32),
209}
210
211impl ThreadState {
212 fn from_raw(raw_state: u32, raw_wait_exception_channel_type: u32) -> Self {
213 match raw_state {
214 sys::ZX_THREAD_STATE_NEW => Self::New,
215 sys::ZX_THREAD_STATE_RUNNING => Self::Running,
216 sys::ZX_THREAD_STATE_SUSPENDED => Self::Suspended,
217 sys::ZX_THREAD_STATE_BLOCKED => Self::Blocked(ThreadBlockType::Unknown),
218 sys::ZX_THREAD_STATE_BLOCKED_EXCEPTION => Self::Blocked(ThreadBlockType::Exception(
219 ExceptionChannelType::from_raw(raw_wait_exception_channel_type),
220 )),
221 sys::ZX_THREAD_STATE_BLOCKED_SLEEPING => Self::Blocked(ThreadBlockType::Sleeping),
222 sys::ZX_THREAD_STATE_BLOCKED_FUTEX => Self::Blocked(ThreadBlockType::Futex),
223 sys::ZX_THREAD_STATE_BLOCKED_PORT => Self::Blocked(ThreadBlockType::Port),
224 sys::ZX_THREAD_STATE_BLOCKED_CHANNEL => Self::Blocked(ThreadBlockType::Channel),
225 sys::ZX_THREAD_STATE_BLOCKED_WAIT_ONE => Self::Blocked(ThreadBlockType::WaitOne),
226 sys::ZX_THREAD_STATE_BLOCKED_WAIT_MANY => Self::Blocked(ThreadBlockType::WaitMany),
227 sys::ZX_THREAD_STATE_BLOCKED_INTERRUPT => Self::Blocked(ThreadBlockType::Interrupt),
228 sys::ZX_THREAD_STATE_BLOCKED_PAGER => Self::Blocked(ThreadBlockType::Pager),
229 sys::ZX_THREAD_STATE_DYING => Self::Dying,
230 sys::ZX_THREAD_STATE_DEAD => Self::Dead,
231 _ => Self::Unknown(raw_state),
232 }
233 }
234}
235
236#[derive(Debug, Copy, Clone, Eq, PartialEq)]
237pub enum ThreadBlockType {
238 Exception(ExceptionChannelType),
239 Sleeping,
240 Futex,
241 Port,
242 Channel,
243 WaitOne,
244 WaitMany,
245 Interrupt,
246 Pager,
247 Unknown,
248}
249
250#[derive(Debug, Copy, Clone, Eq, PartialEq)]
251pub enum ExceptionChannelType {
252 None,
253 Debugger,
254 Thread,
255 Process,
256 Job,
257 JobDebugger,
258 Unknown(u32),
259}
260
261impl ExceptionChannelType {
262 fn from_raw(raw_wait_exception_channel_type: u32) -> Self {
263 match raw_wait_exception_channel_type {
264 sys::ZX_EXCEPTION_CHANNEL_TYPE_NONE => Self::None,
265 sys::ZX_EXCEPTION_CHANNEL_TYPE_DEBUGGER => Self::Debugger,
266 sys::ZX_EXCEPTION_CHANNEL_TYPE_THREAD => Self::Thread,
267 sys::ZX_EXCEPTION_CHANNEL_TYPE_PROCESS => Self::Process,
268 sys::ZX_EXCEPTION_CHANNEL_TYPE_JOB => Self::Job,
269 sys::ZX_EXCEPTION_CHANNEL_TYPE_JOB_DEBUGGER => Self::JobDebugger,
270 _ => Self::Unknown(raw_wait_exception_channel_type),
271 }
272 }
273}