1use core::ffi::{c_char, c_void};
8use core::marker::PhantomData;
9use core::ptr::NonNull;
10use platform_rs::DurationMono;
11use zx_status::Status;
12use zx_types::{zx_instant_mono_t, zx_status_t};
13
14unsafe extern "C" {
15 fn cpp_thread_create_default(
16 name: *const c_char,
17 entry: extern "C" fn(*mut c_void) -> i32,
18 arg: *mut c_void,
19 ) -> *mut c_void;
20 fn cpp_thread_resume(thread: *mut c_void);
21 fn cpp_thread_join(
22 thread: *mut c_void,
23 out_retcode: *mut i32,
24 deadline: zx_instant_mono_t,
25 ) -> i32;
26 fn cpp_thread_current_yield();
27 fn cpp_thread_kill(thread: *mut c_void);
28 fn cpp_thread_is_blocked(thread: *mut c_void) -> bool;
29 fn cpp_thread_current_get() -> *mut c_void;
30 fn cpp_thread_fxt_ref(thread: *mut c_void) -> FxtRef;
31 fn cpp_thread_preempt_set_timeslice_extension(duration: DurationMono) -> bool;
32 fn cpp_thread_preempt_clear_timeslice_extension();
33 fn cpp_thread_preempt_disable();
34 fn cpp_thread_preempt_enable();
35 fn cpp_thread_current_sleep_relative(duration: DurationMono) -> zx_status_t;
36 fn cpp_restricted_enter(vector_table_ptr: usize, context: usize) -> zx_status_t;
37}
38
39#[repr(C)]
42#[derive(Debug, Clone, Copy, PartialEq, Eq)]
43pub struct FxtRef {
44 pub pid: u64,
45 pub tid: u64,
46}
47pub fn restricted_enter(vector_table_ptr: usize, context: usize) -> Result<(), Status> {
51 let status = unsafe { cpp_restricted_enter(vector_table_ptr, context) };
54 Status::ok(status)
55}
56
57#[derive(Debug, Clone, Copy, PartialEq, Eq)]
59pub struct ThreadPtr(NonNull<c_void>);
60
61unsafe impl Send for ThreadPtr {}
64unsafe impl Sync for ThreadPtr {}
65
66impl ThreadPtr {
67 pub const unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
73 match NonNull::new(ptr) {
74 Some(nn) => Some(Self(nn)),
75 None => None,
76 }
77 }
78
79 pub const fn as_raw(self) -> *mut c_void {
81 self.0.as_ptr()
82 }
83
84 pub unsafe fn resume(self) {
90 unsafe { cpp_thread_resume(self.as_raw()) }
91 }
92
93 pub unsafe fn join(self, deadline: zx_instant_mono_t) -> Result<i32, Status> {
101 let mut retcode = 0;
102 let status = unsafe { cpp_thread_join(self.as_raw(), &mut retcode, deadline) };
103 Status::ok(status).map(|_| retcode)
104 }
105
106 pub unsafe fn kill(self) {
112 unsafe { cpp_thread_kill(self.as_raw()) }
113 }
114
115 pub unsafe fn is_blocked(self) -> bool {
122 unsafe { cpp_thread_is_blocked(self.as_raw()) }
123 }
124
125 pub unsafe fn current() -> Self {
132 unsafe { Self::from_raw(cpp_thread_current_get()) }.unwrap()
133 }
134
135 pub unsafe fn fxt_ref(self) -> FxtRef {
142 unsafe { cpp_thread_fxt_ref(self.as_raw()) }
143 }
144}
145
146pub unsafe fn create(
152 name: *const c_char,
153 entry: extern "C" fn(*mut c_void) -> i32,
154 arg: *mut c_void,
155) -> Result<ThreadPtr, Status> {
156 let thread = unsafe { cpp_thread_create_default(name, entry, arg) };
157 unsafe { ThreadPtr::from_raw(thread) }.ok_or(Status::NO_MEMORY)
158}
159
160pub unsafe fn spawn(
167 name: *const c_char,
168 entry: extern "C" fn(*mut c_void) -> i32,
169 arg: *mut c_void,
170) -> Result<ThreadPtr, Status> {
171 let thread = unsafe { create(name, entry, arg)? };
172 unsafe { thread.resume() };
173 Ok(thread)
174}
175
176pub fn r#yield() {
178 unsafe { cpp_thread_current_yield() }
179}
180
181pub fn preempt_disable() {
183 unsafe { cpp_thread_preempt_disable() }
186}
187
188pub fn preempt_enable() {
190 unsafe { cpp_thread_preempt_enable() }
193}
194
195pub fn preempt_set_timeslice_extension(duration: DurationMono) -> bool {
197 unsafe { cpp_thread_preempt_set_timeslice_extension(duration) }
200}
201
202pub fn preempt_clear_timeslice_extension() {
204 unsafe { cpp_thread_preempt_clear_timeslice_extension() }
207}
208
209pub struct AutoPreemptDisabler {
213 disabled: bool,
214 _marker: PhantomData<*mut ()>,
215}
216
217impl AutoPreemptDisabler {
218 pub fn new() -> Self {
220 preempt_disable();
221 Self { disabled: true, _marker: PhantomData }
222 }
223
224 pub fn new_deferred() -> Self {
226 Self { disabled: false, _marker: PhantomData }
227 }
228
229 pub fn disable(&mut self) {
231 if !self.disabled {
232 preempt_disable();
233 self.disabled = true;
234 }
235 }
236
237 pub fn enable(&mut self) {
239 if self.disabled {
240 preempt_enable();
241 self.disabled = false;
242 }
243 }
244
245 pub fn is_disabled(&self) -> bool {
247 self.disabled
248 }
249}
250
251impl Default for AutoPreemptDisabler {
252 fn default() -> Self {
253 Self::new()
254 }
255}
256
257impl Drop for AutoPreemptDisabler {
258 fn drop(&mut self) {
259 self.enable();
260 }
261}
262
263pub struct AutoExpiringPreemptDisabler {
268 should_clear: bool,
269 _marker: PhantomData<*mut ()>,
270}
271
272impl AutoExpiringPreemptDisabler {
273 pub fn new(duration: DurationMono) -> Self {
275 let should_clear = preempt_set_timeslice_extension(duration);
276 Self { should_clear, _marker: PhantomData }
277 }
278}
279
280impl Drop for AutoExpiringPreemptDisabler {
281 fn drop(&mut self) {
282 if self.should_clear {
283 preempt_clear_timeslice_extension();
284 }
285 }
286}
287
288pub fn sleep_relative(duration: DurationMono) -> Result<(), Status> {
290 let status = unsafe { cpp_thread_current_sleep_relative(duration) };
292 Status::ok(status)
293}
294
295#[cfg(test)]
296mod tests {
297 use super::*;
298
299 #[test]
300 fn test_preempt_guards_not_send_or_sync() {
301 fn assert_not_send_sync<T>()
302 where
303 T: ?Sized,
304 {
305 }
306 let _guard = AutoPreemptDisabler::new_deferred();
308 }
309
310 #[test]
311 fn test_auto_preempt_disabler_deferred() {
312 let mut guard = AutoPreemptDisabler::new_deferred();
313 assert!(!guard.is_disabled());
314 guard.disable();
315 assert!(guard.is_disabled());
316 guard.enable();
317 assert!(!guard.is_disabled());
318 }
319
320 #[test]
321 fn test_auto_expiring_preempt_disabler() {
322 let guard = AutoExpiringPreemptDisabler::new(DurationMono(10_000_000));
323 drop(guard);
324 }
325}