Skip to main content

starnix_core/task/
run_state.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 crate::task::{TaskStateCode, Waiter, WaiterRef};
6use starnix_sync::InterruptibleEvent;
7use std::ptr::NonNull;
8
9/// A non-owning reference to an [`InterruptibleEvent`] registered in [`RunState::Event`].
10///
11/// # Safety Invariant
12/// An `EventRef` is only stored in `TaskMutableState::run_state` by
13/// `CurrentTask::run_in_state_internal` for the lexical duration of the blocking callback (while
14/// the `InterruptibleEvent` is borrowed), and is cleared back to `RunState::Running` under
15/// `Task::write()` before `run_in_state_internal` returns. `RunState::wake` is only called under
16/// `Task::read()`, so the pointee is guaranteed to remain valid for every `wake` call.
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub struct EventRef(NonNull<InterruptibleEvent>);
19
20// SAFETY: `EventRef` only provides shared (`&InterruptibleEvent`) access to the pointee, and
21// `InterruptibleEvent` is `Sync`.
22unsafe impl Send for EventRef {}
23// SAFETY: `EventRef` only provides shared (`&InterruptibleEvent`) access to the pointee, and
24// `InterruptibleEvent` is `Sync`.
25unsafe impl Sync for EventRef {}
26
27impl EventRef {
28    /// Creates an [`EventRef`] pointing to `event`.
29    ///
30    /// # Safety
31    /// The caller must ensure that `event` remains valid for as long as the resulting
32    /// `RunState::Event` is installed in `TaskMutableState::run_state` and across all concurrent
33    /// `RunState::wake` calls (by clearing `run_state` back to `RunState::Running` under
34    /// `Task::write()` before `event`'s borrow ends).
35    pub(super) unsafe fn new(event: &InterruptibleEvent) -> Self {
36        Self(NonNull::from(event))
37    }
38
39    unsafe fn interrupt(&self) {
40        // SAFETY: By the `EventRef` invariant and `RunState::wake` safety requirement, `self.0`
41        // points to a live `InterruptibleEvent`.
42        unsafe { self.0.as_ref().interrupt() };
43    }
44}
45
46/// Whether, and how, this task is blocked. This enum can be extended with new
47/// variants to optimize different kinds of waiting.
48#[derive(Debug, Clone, PartialEq)]
49pub enum RunState {
50    /// This task is not blocked.
51    ///
52    /// The task might be running in userspace or kernel.
53    Running,
54
55    /// This thread is blocked in a `Waiter`.
56    Waiter(WaiterRef),
57
58    /// This thread is blocked in an `InterruptibleEvent`.
59    Event(EventRef),
60
61    /// This thread is frozen by a `Waiter`.
62    ///
63    /// When waiting on the `Waiter`, it should have a loop to prevent any signals except
64    /// notification.
65    Frozen(Waiter),
66
67    /// This thread is stopped by a tracer (or stopped by job control).
68    ///
69    /// It is not interruptible except by the tracer or SIGCONT, and can be aborted by SIGKILL.
70    TracingStopped,
71}
72
73impl Default for RunState {
74    fn default() -> Self {
75        RunState::Running
76    }
77}
78
79impl RunState {
80    /// Whether this task is blocked.
81    ///
82    /// If the task is blocked, you can break the task out of the wait using the `wake` function.
83    pub fn is_blocked(&self) -> bool {
84        match self {
85            RunState::Running => false,
86            RunState::Waiter(waiter) => waiter.is_valid(),
87            RunState::Event(_) | RunState::Frozen(_) | RunState::TracingStopped => true,
88        }
89    }
90
91    /// Whether this task ignores signals other than SIGKILL while blocked in this state.
92    pub fn ignores_signals(&self) -> bool {
93        match self {
94            RunState::Frozen(_) | RunState::TracingStopped => true,
95            RunState::Running | RunState::Waiter(_) | RunState::Event(_) => false,
96        }
97    }
98
99    /// Unblock the task by interrupting whatever wait the task is blocked upon.
100    ///
101    /// # Safety
102    /// If `self` is `RunState::Event`, the caller must guarantee that the target task has not yet
103    /// cleared its `run_state` in `CurrentTask::run_in_state_internal` (for example, by holding
104    /// the task's state lock while reading `run_state` and calling `wake`).
105    pub(super) unsafe fn wake(&self) {
106        match self {
107            RunState::Running => (),
108            RunState::Waiter(waiter) => waiter.interrupt(),
109            // SAFETY: Guaranteed by the caller.
110            RunState::Event(event) => unsafe { event.interrupt() },
111            // When frozen or stopped, the task is immune to any interrupts.
112            RunState::Frozen(_) | RunState::TracingStopped => (),
113        }
114    }
115
116    /// The TaskStateCode corresponding to the RunState.
117    pub fn state_code(&self) -> TaskStateCode {
118        match self {
119            RunState::Running => TaskStateCode::Running,
120            RunState::Waiter(waiter) => {
121                if waiter.is_valid() {
122                    TaskStateCode::Sleeping
123                } else {
124                    TaskStateCode::Running
125                }
126            }
127            RunState::Event(_) | RunState::Frozen(_) => TaskStateCode::Sleeping,
128            // TODO(https://fxbug.dev/566829060): Job-control stops currently report
129            // `TaskStateCode::TracingStop` ('t'). Distinguish them to report
130            // `TaskStateCode::Stopped` ('T').
131            RunState::TracingStopped => TaskStateCode::TracingStop,
132        }
133    }
134}