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}