Skip to main content

kernel/
thread.rs

1// Copyright 2026 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use core::ffi::{c_char, c_void};
6use core::ptr::NonNull;
7use zx_status::Status;
8use zx_types::zx_instant_mono_t;
9
10unsafe extern "C" {
11    fn cpp_thread_create_default(
12        name: *const c_char,
13        entry: extern "C" fn(*mut c_void) -> i32,
14        arg: *mut c_void,
15    ) -> *mut c_void;
16    fn cpp_thread_resume(thread: *mut c_void);
17    fn cpp_thread_join(
18        thread: *mut c_void,
19        out_retcode: *mut i32,
20        deadline: zx_instant_mono_t,
21    ) -> i32;
22    fn cpp_thread_current_yield();
23    fn cpp_thread_kill(thread: *mut c_void);
24    fn cpp_thread_is_blocked(thread: *mut c_void) -> bool;
25    fn cpp_thread_current_get() -> *mut c_void;
26    fn cpp_thread_fxt_ref(thread: *mut c_void) -> FxtRef;
27}
28
29// LINT.IfChange(FxtRef)
30/// Rust representation of the C++ `FxtRef` struct.
31#[repr(C)]
32#[derive(Debug, Clone, Copy, PartialEq, Eq)]
33pub struct FxtRef {
34    pub pid: u64,
35    pub tid: u64,
36}
37// LINT.ThenChange(//zircon/kernel/kernel/thread_ffi.cc:FxtRef)
38
39/// Type-safe wrapper around a raw pointer to a Zircon kernel Thread.
40#[derive(Debug, Clone, Copy, PartialEq, Eq)]
41pub struct ThreadPtr(NonNull<c_void>);
42
43// SAFETY: A ThreadPtr is just a pointer to a kernel thread, which can be safely passed
44// between threads to perform join or kill operations.
45unsafe impl Send for ThreadPtr {}
46unsafe impl Sync for ThreadPtr {}
47
48impl ThreadPtr {
49    /// Creates a `ThreadPtr` from a raw pointer.
50    ///
51    /// # Safety
52    ///
53    /// The caller must ensure that `ptr` is a valid pointer to a live kernel thread.
54    pub const unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
55        match NonNull::new(ptr) {
56            Some(nn) => Some(Self(nn)),
57            None => None,
58        }
59    }
60
61    /// Returns the raw pointer.
62    pub const fn as_raw(self) -> *mut c_void {
63        self.0.as_ptr()
64    }
65
66    /// Resumes execution of the thread.
67    ///
68    /// # Safety
69    ///
70    /// The caller must ensure the thread has not been joined or destroyed.
71    pub unsafe fn resume(self) {
72        unsafe { cpp_thread_resume(self.as_raw()) }
73    }
74
75    /// Joins the thread, waiting for it to exit.
76    ///
77    /// Returns the thread's return code on success.
78    ///
79    /// # Safety
80    ///
81    /// The caller must ensure that the thread has not been joined yet.
82    pub unsafe fn join(self, deadline: zx_instant_mono_t) -> Result<i32, Status> {
83        let mut retcode = 0;
84        let status = unsafe { cpp_thread_join(self.as_raw(), &mut retcode, deadline) };
85        Status::ok(status).map(|_| retcode)
86    }
87
88    /// Kills the thread.
89    ///
90    /// # Safety
91    ///
92    /// The caller must ensure the thread is still valid.
93    pub unsafe fn kill(self) {
94        unsafe { cpp_thread_kill(self.as_raw()) }
95    }
96
97    /// Checks if the thread is currently blocked.
98    ///
99    /// # Safety
100    ///
101    /// The caller must ensure that the thread pointer is still valid and the
102    /// underlying thread has not been destroyed or joined.
103    pub unsafe fn is_blocked(self) -> bool {
104        unsafe { cpp_thread_is_blocked(self.as_raw()) }
105    }
106
107    /// Returns a `ThreadPtr` representing the currently executing thread.
108    ///
109    /// # Safety
110    ///
111    /// The caller must ensure that this function is called after multi-threading has been
112    /// initialized (i.e. after LK_INIT_LEVEL_THREADING).
113    pub unsafe fn current() -> Self {
114        unsafe { Self::from_raw(cpp_thread_current_get()) }.unwrap()
115    }
116
117    /// Returns the thread's process and thread KOIDs.
118    ///
119    /// # Safety
120    ///
121    /// The caller must ensure that the thread pointer is still valid and the
122    /// underlying thread has not been destroyed.
123    pub unsafe fn fxt_ref(self) -> FxtRef {
124        unsafe { cpp_thread_fxt_ref(self.as_raw()) }
125    }
126}
127
128/// Creates a new kernel thread with default priority.
129///
130/// # Safety
131///
132/// The caller must ensure that `entry` and `arg` are safe to run on a new thread.
133pub unsafe fn create(
134    name: *const c_char,
135    entry: extern "C" fn(*mut c_void) -> i32,
136    arg: *mut c_void,
137) -> Result<ThreadPtr, Status> {
138    let thread = unsafe { cpp_thread_create_default(name, entry, arg) };
139    unsafe { ThreadPtr::from_raw(thread) }.ok_or(Status::NO_MEMORY)
140}
141
142/// Spawns a new kernel thread with default priority and resumes it.
143///
144/// # Safety
145///
146/// The caller must ensure that `entry` and `arg` are safe to run on a new thread,
147/// and that the thread is joined before any borrowed data in `arg` is destroyed.
148pub unsafe fn spawn(
149    name: *const c_char,
150    entry: extern "C" fn(*mut c_void) -> i32,
151    arg: *mut c_void,
152) -> Result<ThreadPtr, Status> {
153    let thread = unsafe { create(name, entry, arg)? };
154    unsafe { thread.resume() };
155    Ok(thread)
156}
157
158/// Yields the current thread's CPU time slice.
159pub fn r#yield() {
160    unsafe { cpp_thread_current_yield() }
161}