Skip to main content

kernel/
thread.rs

1// Copyright 2026 The Fuchsia Authors
2//
3// Use of this source code is governed by a MIT-style
4// license that can be found in the LICENSE file or at
5// https://opensource.org/licenses/MIT
6
7use 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// LINT.IfChange(FxtRef)
40/// Rust representation of the C++ `FxtRef` struct.
41#[repr(C)]
42#[derive(Debug, Clone, Copy, PartialEq, Eq)]
43pub struct FxtRef {
44    pub pid: u64,
45    pub tid: u64,
46}
47// LINT.ThenChange(//zircon/kernel/kernel/thread_ffi.cc:FxtRef)
48
49/// Enters restricted mode using the given vector table pointer and context.
50pub fn restricted_enter(vector_table_ptr: usize, context: usize) -> Result<(), Status> {
51    // SAFETY: `cpp_restricted_enter` performs validation of vector_table_ptr and context
52    // in architecture-specific restricted mode entry routines.
53    let status = unsafe { cpp_restricted_enter(vector_table_ptr, context) };
54    Status::ok(status)
55}
56
57/// Type-safe wrapper around a raw pointer to a Zircon kernel Thread.
58#[derive(Debug, Clone, Copy, PartialEq, Eq)]
59pub struct ThreadPtr(NonNull<c_void>);
60
61// SAFETY: A ThreadPtr is just a pointer to a kernel thread, which can be safely passed
62// between threads to perform join or kill operations.
63unsafe impl Send for ThreadPtr {}
64unsafe impl Sync for ThreadPtr {}
65
66impl ThreadPtr {
67    /// Creates a `ThreadPtr` from a raw pointer.
68    ///
69    /// # Safety
70    ///
71    /// The caller must ensure that `ptr` is a valid pointer to a live kernel thread.
72    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    /// Returns the raw pointer.
80    pub const fn as_raw(self) -> *mut c_void {
81        self.0.as_ptr()
82    }
83
84    /// Resumes execution of the thread.
85    ///
86    /// # Safety
87    ///
88    /// The caller must ensure the thread has not been joined or destroyed.
89    pub unsafe fn resume(self) {
90        unsafe { cpp_thread_resume(self.as_raw()) }
91    }
92
93    /// Joins the thread, waiting for it to exit.
94    ///
95    /// Returns the thread's return code on success.
96    ///
97    /// # Safety
98    ///
99    /// The caller must ensure that the thread has not been joined yet.
100    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    /// Kills the thread.
107    ///
108    /// # Safety
109    ///
110    /// The caller must ensure the thread is still valid.
111    pub unsafe fn kill(self) {
112        unsafe { cpp_thread_kill(self.as_raw()) }
113    }
114
115    /// Checks if the thread is currently blocked.
116    ///
117    /// # Safety
118    ///
119    /// The caller must ensure that the thread pointer is still valid and the
120    /// underlying thread has not been destroyed or joined.
121    pub unsafe fn is_blocked(self) -> bool {
122        unsafe { cpp_thread_is_blocked(self.as_raw()) }
123    }
124
125    /// Returns a `ThreadPtr` representing the currently executing thread.
126    ///
127    /// # Safety
128    ///
129    /// The caller must ensure that this function is called after multi-threading has been
130    /// initialized (i.e. after LK_INIT_LEVEL_THREADING).
131    pub unsafe fn current() -> Self {
132        unsafe { Self::from_raw(cpp_thread_current_get()) }.unwrap()
133    }
134
135    /// Returns the thread's process and thread KOIDs.
136    ///
137    /// # Safety
138    ///
139    /// The caller must ensure that the thread pointer is still valid and the
140    /// underlying thread has not been destroyed.
141    pub unsafe fn fxt_ref(self) -> FxtRef {
142        unsafe { cpp_thread_fxt_ref(self.as_raw()) }
143    }
144}
145
146/// Creates a new kernel thread with default priority.
147///
148/// # Safety
149///
150/// The caller must ensure that `entry` and `arg` are safe to run on a new thread.
151pub 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
160/// Spawns a new kernel thread with default priority and resumes it.
161///
162/// # Safety
163///
164/// The caller must ensure that `entry` and `arg` are safe to run on a new thread,
165/// and that the thread is joined before any borrowed data in `arg` is destroyed.
166pub 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
176/// Yields the current thread's CPU time slice.
177pub fn r#yield() {
178    unsafe { cpp_thread_current_yield() }
179}
180
181/// Disables preemption on the current thread.
182pub fn preempt_disable() {
183    // SAFETY: Calling this FFI function safely increments the preemption disable count for the
184    // current thread.
185    unsafe { cpp_thread_preempt_disable() }
186}
187
188/// Re-enables preemption on the current thread.
189pub fn preempt_enable() {
190    // SAFETY: Calling this FFI function safely decrements the preemption disable count for the
191    // current thread.
192    unsafe { cpp_thread_preempt_enable() }
193}
194
195/// Sets a timeslice extension on the current thread's preemption state.
196pub fn preempt_set_timeslice_extension(duration: DurationMono) -> bool {
197    // SAFETY: Calling this FFI function safely sets the timeslice extension on the current thread's
198    // preemption state.
199    unsafe { cpp_thread_preempt_set_timeslice_extension(duration) }
200}
201
202/// Clears an expiring timeslice extension on the current thread's preemption state.
203pub fn preempt_clear_timeslice_extension() {
204    // SAFETY: Calling this FFI function safely clears the timeslice extension on the current
205    // thread's preemption state.
206    unsafe { cpp_thread_preempt_clear_timeslice_extension() }
207}
208
209/// RAII guard that disables preemption for its scope.
210///
211/// This guard is `!Send` and `!Sync` because preemption state is CPU- and thread-local.
212pub struct AutoPreemptDisabler {
213    disabled: bool,
214    _marker: PhantomData<*mut ()>,
215}
216
217impl AutoPreemptDisabler {
218    /// Creates a new guard and immediately disables preemption.
219    pub fn new() -> Self {
220        preempt_disable();
221        Self { disabled: true, _marker: PhantomData }
222    }
223
224    /// Creates a new guard without immediately disabling preemption.
225    pub fn new_deferred() -> Self {
226        Self { disabled: false, _marker: PhantomData }
227    }
228
229    /// Disables preemption if not already disabled by this guard instance.
230    pub fn disable(&mut self) {
231        if !self.disabled {
232            preempt_disable();
233            self.disabled = true;
234        }
235    }
236
237    /// Re-enables preemption if previously disabled by this guard instance.
238    pub fn enable(&mut self) {
239        if self.disabled {
240            preempt_enable();
241            self.disabled = false;
242        }
243    }
244
245    /// Returns whether preemption is currently disabled by this guard instance.
246    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
263/// RAII guard that sets a timeslice extension for its scope.
264///
265/// This guard is `!Send` and `!Sync` because timeslice extensions modify CPU- and thread-local
266/// state.
267pub struct AutoExpiringPreemptDisabler {
268    should_clear: bool,
269    _marker: PhantomData<*mut ()>,
270}
271
272impl AutoExpiringPreemptDisabler {
273    /// Creates a new guard and attempts to set a timeslice extension for `duration`.
274    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
288/// Sleeps the current thread for the specified relative duration.
289pub fn sleep_relative(duration: DurationMono) -> Result<(), Status> {
290    // SAFETY: cpp_thread_current_sleep_relative is safe to call at any time in thread context.
291    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        // Verification that the types compile and can be instantiated safely in unit tests.
307        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}