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}