blob: b868f187337dbebaa1f61e93bfaee3d6f39f4be3 [file]
// Copyright 2026 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
use crate::platform_rs::timer::{DurationMono, InstantMono};
use core::ffi::{c_char, c_void};
use core::marker::PhantomData;
use core::ptr::NonNull;
use zx_status::Status;
use zx_types::{zx_instant_mono_t, zx_status_t};
use crate::kernel::restricted_state::RestrictedState;
use crate::kernel::scheduler_state::SchedulerStateBaseProfile;
use crate::vm::vm_aspace::VmAspace;
#[allow(improper_ctypes)]
unsafe extern "C" {
fn cpp_thread_create_default(
name: *const c_char,
entry: extern "C" fn(*mut c_void) -> i32,
arg: *mut c_void,
) -> *mut Thread;
fn cpp_thread_create_with_priority(
name: *const c_char,
entry: extern "C" fn(*mut c_void) -> i32,
arg: *mut c_void,
priority: i32,
) -> *mut Thread;
fn cpp_thread_create_with_profile(
name_ptr: *const c_char,
name_len: usize,
entry: extern "C" fn(*mut c_void) -> i32,
arg: *mut c_void,
profile: *const SchedulerStateBaseProfile,
) -> *mut Thread;
fn cpp_thread_resume(thread: *mut Thread);
fn cpp_thread_join(
thread: *mut Thread,
out_retcode: *mut i32,
deadline: zx_instant_mono_t,
) -> i32;
fn cpp_thread_current_yield();
fn cpp_thread_kill(thread: *mut Thread);
fn cpp_thread_suspend(thread: *mut Thread) -> zx_status_t;
fn cpp_thread_is_blocked(thread: *mut Thread) -> bool;
fn cpp_thread_current_get() -> *mut Thread;
fn cpp_thread_current_active_aspace() -> *mut VmAspace;
fn cpp_thread_fxt_ref(thread: *mut Thread) -> FxtRef;
fn cpp_thread_preempt_set_timeslice_extension(duration: DurationMono) -> bool;
fn cpp_thread_preempt_clear_timeslice_extension();
fn cpp_thread_preempt_disable();
fn cpp_thread_preempt_enable();
fn cpp_thread_preempt();
fn cpp_thread_current_sleep_relative(duration: DurationMono) -> zx_status_t;
fn cpp_thread_current_sleep_etc(
deadline: *const crate::kernel::deadline::Deadline,
interruptible: Interruptible,
now: zx_instant_mono_t,
) -> zx_status_t;
fn cpp_thread_current_soft_fault(va: usize, flags: u32) -> zx_status_t;
fn cpp_thread_get_arch(thread: *mut Thread) -> *mut c_void;
fn cpp_thread_get_stack_top(thread: *mut Thread) -> usize;
fn cpp_thread_get_shadow_call_base(thread: *mut Thread) -> usize;
fn cpp_thread_dump_current_stack();
fn cpp_thread_is_user_state_saved(thread: *mut Thread) -> bool;
fn cpp_thread_is_running(thread: *const Thread) -> bool;
fn cpp_thread_name(thread: *const Thread) -> *const c_char;
fn cpp_thread_process_pending_signals(frame: *mut c_void);
fn cpp_thread_is_in_restricted_mode(thread: *mut Thread) -> bool;
fn cpp_thread_current_restricted_state() -> *mut RestrictedState;
fn cpp_thread_current_set_restricted_state(raw_rs: *mut RestrictedState);
fn cpp_thread_current_is_signaled() -> bool;
fn cpp_thread_current_check_for_restricted_kick() -> bool;
}
pub const THREAD_SIGNAL_KILL: u32 = 1 << 0;
pub const THREAD_SIGNAL_SUSPEND: u32 = 1 << 1;
pub const THREAD_SIGNAL_POLICY_EXCEPTION: u32 = 1 << 2;
pub const THREAD_SIGNAL_RESTRICTED_KICK: u32 = 1 << 3;
pub const THREAD_SIGNAL_SAMPLE_STACK: u32 = 1 << 4;
pub const THREAD_SIGNAL_CHECK_RSEQ: u32 = 1 << 5;
// LINT.IfChange(FxtRef)
/// Rust representation of the C++ `FxtRef` struct.
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct FxtRef {
pub pid: u64,
pub tid: u64,
}
// LINT.ThenChange(//zircon/kernel/kernel/thread_ffi.cc:FxtRef)
/// An opaque type representing the C++ `Thread` class.
#[repr(C)]
pub struct Thread {
_private: [u8; 0],
}
/// Enters restricted mode using the given vector table pointer and context.
pub fn restricted_enter(vector_table_ptr: usize, context: usize) -> Result<(), Status> {
crate::kernel::restricted::restricted_enter(vector_table_ptr, context)
}
/// Type-safe wrapper around a raw pointer to a Zircon kernel Thread.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ThreadPtr(NonNull<Thread>);
// SAFETY: A ThreadPtr is just a pointer to a kernel thread, which can be safely passed
// between threads to perform join or kill operations.
unsafe impl Send for ThreadPtr {}
unsafe impl Sync for ThreadPtr {}
impl ThreadPtr {
/// Creates a `ThreadPtr` from a raw pointer.
///
/// # Safety
///
/// The caller must ensure that `ptr` is a valid pointer to a live kernel thread.
pub const unsafe fn from_raw(ptr: *mut Thread) -> Option<Self> {
match NonNull::new(ptr) {
Some(nn) => Some(Self(nn)),
None => None,
}
}
/// Returns the raw pointer.
pub const fn as_raw(self) -> *mut Thread {
self.0.as_ptr()
}
/// Returns the raw const pointer.
pub const fn as_ptr(self) -> *const Thread {
self.0.as_ptr()
}
/// Resumes execution of the thread.
///
/// # Safety
///
/// The caller must ensure the thread has not been joined or destroyed.
pub unsafe fn resume(self) {
unsafe { cpp_thread_resume(self.as_raw()) }
}
/// Joins the thread, waiting for it to exit.
///
/// Returns the thread's return code on success.
///
/// # Safety
///
/// The caller must ensure that the thread has not been joined yet.
pub unsafe fn join(self, deadline: InstantMono) -> Result<i32, Status> {
let mut retcode = 0;
let status = unsafe { cpp_thread_join(self.as_raw(), &mut retcode, deadline.0) };
Status::ok(status).map(|_| retcode)
}
/// Kills the thread.
///
/// # Safety
///
/// The caller must ensure the thread is still valid.
pub unsafe fn kill(self) {
unsafe { cpp_thread_kill(self.as_raw()) }
}
/// Suspends execution of the thread.
///
/// # Safety
///
/// The caller must ensure the thread is still valid.
pub unsafe fn suspend(self) -> Result<(), Status> {
let status = unsafe { cpp_thread_suspend(self.as_raw()) };
Status::ok(status)
}
/// Checks if the thread is currently blocked.
///
/// # Safety
///
/// The caller must ensure that the thread pointer is still valid and the
/// underlying thread has not been destroyed or joined.
pub unsafe fn is_blocked(self) -> bool {
unsafe { cpp_thread_is_blocked(self.as_raw()) }
}
/// Returns a `ThreadPtr` representing the currently executing thread.
///
/// # Safety
///
/// The caller must ensure that this function is called after multi-threading has been
/// initialized (i.e. after LK_INIT_LEVEL_THREADING).
pub unsafe fn current() -> Self {
unsafe { Self::from_raw(cpp_thread_current_get()) }.unwrap()
}
/// Returns the thread's process and thread KOIDs.
///
/// # Safety
///
/// The caller must ensure that the thread pointer is still valid and the
/// underlying thread has not been destroyed.
pub unsafe fn fxt_ref(self) -> FxtRef {
unsafe { cpp_thread_fxt_ref(self.as_raw()) }
}
}
/// Creates a new kernel thread with default priority.
///
/// # Safety
///
/// The caller must ensure that `entry` and `arg` are safe to run on a new thread.
pub unsafe fn create(
name: *const c_char,
entry: extern "C" fn(*mut c_void) -> i32,
arg: *mut c_void,
) -> Result<ThreadPtr, Status> {
let thread = unsafe { cpp_thread_create_default(name, entry, arg) };
unsafe { ThreadPtr::from_raw(thread) }.ok_or(Status::NO_MEMORY)
}
/// Kernel thread priority levels matching Zircon C++ definitions in `<kernel/thread.h>`.
pub const LOW_PRIORITY: i32 = 8;
pub const DEFAULT_PRIORITY: i32 = 16;
pub const HIGH_PRIORITY: i32 = 24;
/// Creates a new kernel thread with the specified priority.
///
/// # Safety
///
/// The caller must ensure that `entry` and `arg` are safe to run on a new thread.
pub unsafe fn create_with_priority(
name: *const c_char,
entry: extern "C" fn(*mut c_void) -> i32,
arg: *mut c_void,
priority: i32,
) -> Result<ThreadPtr, Status> {
let thread = unsafe { cpp_thread_create_with_priority(name, entry, arg, priority) };
unsafe { ThreadPtr::from_raw(thread) }.ok_or(Status::NO_MEMORY)
}
/// Creates a new thread with the given base profile.
///
/// # Safety
///
/// The caller must ensure that `entry` and `arg` are safe to run on a new thread.
pub unsafe fn create_with_profile(
name: &[u8],
entry: extern "C" fn(*mut c_void) -> i32,
arg: *mut c_void,
profile: &SchedulerStateBaseProfile,
) -> Result<ThreadPtr, Status> {
let thread = unsafe {
cpp_thread_create_with_profile(
name.as_ptr() as *const c_char,
name.len(),
entry,
arg,
profile,
)
};
unsafe { ThreadPtr::from_raw(thread) }.ok_or(Status::NO_MEMORY)
}
/// Spawns a new kernel thread with default priority and resumes it.
///
/// # Safety
///
/// The caller must ensure that `entry` and `arg` are safe to run on a new thread,
/// and that the thread is joined before any borrowed data in `arg` is destroyed.
pub unsafe fn spawn(
name: *const c_char,
entry: extern "C" fn(*mut c_void) -> i32,
arg: *mut c_void,
) -> Result<ThreadPtr, Status> {
let thread = unsafe { create(name, entry, arg)? };
unsafe { thread.resume() };
Ok(thread)
}
/// Yields the current thread's CPU time slice.
pub fn r#yield() {
unsafe { cpp_thread_current_yield() }
}
/// Disables preemption on the current thread.
pub fn preempt_disable() {
// SAFETY: Calling this FFI function safely increments the preemption disable count for the
// current thread.
unsafe { cpp_thread_preempt_disable() }
}
/// Re-enables preemption on the current thread.
pub fn preempt_enable() {
// SAFETY: Calling this FFI function safely decrements the preemption disable count for the
// current thread.
unsafe { cpp_thread_preempt_enable() }
}
/// Sets a timeslice extension on the current thread's preemption state.
pub fn preempt_set_timeslice_extension(duration: DurationMono) -> bool {
// SAFETY: Calling this FFI function safely sets the timeslice extension on the current thread's
// preemption state.
unsafe { cpp_thread_preempt_set_timeslice_extension(duration) }
}
/// Clears an expiring timeslice extension on the current thread's preemption state.
pub fn preempt_clear_timeslice_extension() {
// SAFETY: Calling this FFI function safely clears the timeslice extension on the current
// thread's preemption state.
unsafe { cpp_thread_preempt_clear_timeslice_extension() }
}
/// RAII guard that disables preemption for its scope.
///
/// This guard is `!Send` and `!Sync` because preemption state is CPU- and thread-local.
pub struct AutoPreemptDisabler {
disabled: bool,
_marker: PhantomData<*mut ()>,
}
impl AutoPreemptDisabler {
/// Creates a new guard and immediately disables preemption.
pub fn new() -> Self {
preempt_disable();
Self { disabled: true, _marker: PhantomData }
}
/// Creates a new guard without immediately disabling preemption.
pub fn new_deferred() -> Self {
Self { disabled: false, _marker: PhantomData }
}
/// Disables preemption if not already disabled by this guard instance.
pub fn disable(&mut self) {
if !self.disabled {
preempt_disable();
self.disabled = true;
}
}
/// Re-enables preemption if previously disabled by this guard instance.
pub fn enable(&mut self) {
if self.disabled {
preempt_enable();
self.disabled = false;
}
}
/// Returns whether preemption is currently disabled by this guard instance.
pub fn is_disabled(&self) -> bool {
self.disabled
}
}
impl Default for AutoPreemptDisabler {
fn default() -> Self {
Self::new()
}
}
impl Drop for AutoPreemptDisabler {
fn drop(&mut self) {
self.enable();
}
}
/// RAII guard that sets a timeslice extension for its scope.
///
/// This guard is `!Send` and `!Sync` because timeslice extensions modify CPU- and thread-local
/// state.
pub struct AutoExpiringPreemptDisabler {
should_clear: bool,
_marker: PhantomData<*mut ()>,
}
impl AutoExpiringPreemptDisabler {
/// Creates a new guard and attempts to set a timeslice extension for `duration`.
pub fn new(duration: DurationMono) -> Self {
let should_clear = preempt_set_timeslice_extension(duration);
Self { should_clear, _marker: PhantomData }
}
}
impl Drop for AutoExpiringPreemptDisabler {
fn drop(&mut self) {
if self.should_clear {
preempt_clear_timeslice_extension();
}
}
}
/// Whether a block or sleep operation can be interrupted, matching C++ `Interruptible`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct Interruptible(pub bool);
zr::static_assert!(core::mem::size_of::<Interruptible>() == 1);
zr::static_assert!(core::mem::align_of::<Interruptible>() == 1);
impl Interruptible {
pub const NO: Self = Self(false);
pub const YES: Self = Self(true);
/// Converts the `Interruptible` setting to a boolean value (`Interruptible::YES` is `true`).
#[inline]
pub const fn as_bool(self) -> bool {
self.0
}
}
impl From<Interruptible> for bool {
#[inline]
fn from(i: Interruptible) -> bool {
i.0
}
}
impl From<bool> for Interruptible {
#[inline]
fn from(b: bool) -> Interruptible {
Interruptible(b)
}
}
/// Sleeps the current thread for the specified relative duration.
pub fn sleep_relative(duration: DurationMono) -> Result<(), Status> {
// SAFETY: cpp_thread_current_sleep_relative is safe to call at any time in thread context.
let status = unsafe { cpp_thread_current_sleep_relative(duration) };
Status::ok(status)
}
/// Sleeps the current thread until the specified deadline with timer slack.
pub fn sleep_etc(
deadline: &crate::kernel::deadline::Deadline,
interruptible: Interruptible,
now: zx_instant_mono_t,
) -> Result<(), Status> {
// SAFETY: `deadline` points to a valid `Deadline`.
let status = unsafe { cpp_thread_current_sleep_etc(deadline as *const _, interruptible, now) };
Status::ok(status)
}
/// Soft faults a page at the given virtual address for the current thread.
pub fn soft_fault(va: usize, flags: u32) -> Result<(), Status> {
// SAFETY: cpp_thread_current_soft_fault is safe to call from thread context.
let status = unsafe { cpp_thread_current_soft_fault(va, flags) };
Status::ok(status)
}
/// Returns the raw pointer to the current thread.
pub fn current_get() -> *mut Thread {
unsafe { cpp_thread_current_get() }
}
/// Triggers preemption on the current thread.
pub fn preempt() {
unsafe { cpp_thread_preempt() }
}
/// Dumps the call stack of the current thread.
pub fn dump_current_stack() {
unsafe { cpp_thread_dump_current_stack() }
}
/// Processes pending signals on the current thread using the given iframe.
///
/// # Safety
/// Caller must ensure `frame` points to a valid architectural `iframe_t`.
pub unsafe fn process_pending_signals(frame: *mut c_void) {
// SAFETY: Forwarded to C++ Thread::Current::ProcessPendingSignals with caller-verified frame.
unsafe { cpp_thread_process_pending_signals(frame) }
}
/// Returns a pointer to the architecture-specific state (`arch_thread`) of `thread`.
///
/// The returned pointer is derived by offset only, so this is safe to call before
/// `thread` is fully constructed; dereferencing the result is the caller's problem.
///
/// # Safety
/// Caller must ensure `thread` points to a C++ `Thread` instance.
pub unsafe fn get_arch(thread: *mut Thread) -> *mut c_void {
// SAFETY: Forwarded to C++ Thread::arch() with caller-verified pointer.
unsafe { cpp_thread_get_arch(thread) }
}
/// Returns the top of the stack for `thread`.
///
/// # Safety
/// Caller must ensure `thread` points to a valid C++ `Thread` instance.
pub unsafe fn get_stack_top(thread: *mut Thread) -> usize {
// SAFETY: Forwarded to C++ Thread::stack().top() with caller-verified pointer.
unsafe { cpp_thread_get_stack_top(thread) }
}
/// Returns the shadow call stack base for `thread`.
///
/// # Safety
/// Caller must ensure `thread` points to a valid C++ `Thread` instance.
pub unsafe fn get_shadow_call_base(thread: *mut Thread) -> usize {
// SAFETY: Forwarded to C++ Thread::stack().shadow_call_base() with caller-verified pointer.
unsafe { cpp_thread_get_shadow_call_base(thread) }
}
/// Checks whether user state is saved for `thread`.
///
/// # Safety
/// Caller must ensure `thread` points to a valid C++ `Thread` instance whose thread lock is held.
pub unsafe fn is_user_state_saved(thread: *mut Thread) -> bool {
// SAFETY: Forwarded to C++ Thread::IsUserStateSavedLocked() with caller-verified pointer.
unsafe { cpp_thread_is_user_state_saved(thread) }
}
/// Checks whether `thread` is currently running.
///
/// # Safety
/// Caller must ensure `thread` points to a valid C++ `Thread` instance.
pub unsafe fn is_running(thread: *const Thread) -> bool {
// SAFETY: Forwarded to C++ Thread::state() with caller-verified pointer.
unsafe { cpp_thread_is_running(thread) }
}
/// Returns the name of `thread`.
///
/// # Safety
/// Caller must ensure `thread` points to a valid C++ `Thread` instance.
pub unsafe fn name(thread: *const Thread) -> *const c_char {
// SAFETY: Forwarded to C++ Thread::name() with caller-verified pointer.
unsafe { cpp_thread_name(thread) }
}
/// Checks whether `thread` is executing in restricted mode.
///
/// # Safety
/// Caller must ensure `thread` points to a valid C++ `Thread` instance.
pub unsafe fn is_in_restricted_mode(thread: *mut Thread) -> bool {
// SAFETY: Forwarded to C++ Thread restricted state query with caller-verified pointer.
unsafe { cpp_thread_is_in_restricted_mode(thread) }
}
/// Returns the current thread's restricted mode state pointer.
pub fn current_restricted_state() -> *mut RestrictedState {
// SAFETY: Foreign function wrapper for Thread::Current::restricted_state().
unsafe { cpp_thread_current_restricted_state() }
}
/// The current address space this thread is associated with. This can be None if this is a kernel
/// thread.
///
/// # Safety
///
/// The caller must ensure that the returned address space reference remains valid for lifetime
/// `'a`.
pub unsafe fn current_active_aspace<'a>() -> Option<&'a VmAspace> {
// SAFETY: `cpp_thread_current_active_aspace` returns the active `VmAspace*` pointer, which
// is guaranteed by the caller to remain valid for `'a`.
unsafe { cpp_thread_current_active_aspace().as_ref() }
}
/// Sets the current thread's restricted mode state pointer.
///
/// # Safety
/// Caller must pass a valid `RestrictedState` raw pointer or null pointer.
pub unsafe fn current_set_restricted_state(raw_rs: *mut RestrictedState) {
// SAFETY: Forwarded to C++ Thread::Current::Get()->set_restricted_state.
unsafe { cpp_thread_current_set_restricted_state(raw_rs) }
}
/// Returns whether the current thread is signaled.
pub fn current_is_signaled() -> bool {
// SAFETY: Foreign function wrapper for Thread::Current::Get()->IsSignaled().
unsafe { cpp_thread_current_is_signaled() }
}
/// Checks and clears the current thread's restricted kick flag.
pub fn current_check_for_restricted_kick() -> bool {
// SAFETY: Foreign function wrapper for Thread::Current::CheckForRestrictedKick().
unsafe { cpp_thread_current_check_for_restricted_kick() }
}