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::sync::Arc;
8
9/// Whether, and how, this task is blocked. This enum can be extended with new
10/// variants to optimize different kinds of waiting.
11#[derive(Debug, Clone)]
12pub enum RunState {
13    /// This task is not blocked.
14    ///
15    /// The task might be running in userspace or kernel.
16    Running,
17
18    /// This thread is blocked in a `Waiter`.
19    Waiter(WaiterRef),
20
21    /// This thread is blocked in an `InterruptibleEvent`.
22    Event(Arc<InterruptibleEvent>),
23
24    /// This thread is frozen by a `Waiter`.
25    ///
26    /// When waiting on the `Waiter`, it should have a loop to prevent any signals except
27    /// notification.
28    Frozen(Waiter),
29
30    /// This thread is stopped by a tracer (or stopped by job control).
31    ///
32    /// It is not interruptible except by the tracer or SIGCONT, and can be aborted by SIGKILL.
33    TracingStopped,
34}
35
36impl Default for RunState {
37    fn default() -> Self {
38        RunState::Running
39    }
40}
41
42impl RunState {
43    /// Whether this task is blocked.
44    ///
45    /// If the task is blocked, you can break the task out of the wait using the `wake` function.
46    pub fn is_blocked(&self) -> bool {
47        match self {
48            RunState::Running => false,
49            RunState::Waiter(waiter) => waiter.is_valid(),
50            RunState::Event(_) | RunState::Frozen(_) | RunState::TracingStopped => true,
51        }
52    }
53
54    /// Whether this task ignores signals other than SIGKILL while blocked in this state.
55    pub fn ignores_signals(&self) -> bool {
56        match self {
57            RunState::Frozen(_) | RunState::TracingStopped => true,
58            RunState::Running | RunState::Waiter(_) | RunState::Event(_) => false,
59        }
60    }
61
62    /// Unblock the task by interrupting whatever wait the task is blocked upon.
63    pub fn wake(&self) {
64        match self {
65            RunState::Running => (),
66            RunState::Waiter(waiter) => waiter.interrupt(),
67            RunState::Event(event) => event.interrupt(),
68            // When frozen or stopped, the task is immune to any interrupts.
69            RunState::Frozen(_) | RunState::TracingStopped => (),
70        }
71    }
72
73    /// The TaskStateCode corresponding to the RunState.
74    pub fn state_code(&self) -> TaskStateCode {
75        match self {
76            RunState::Running => TaskStateCode::Running,
77            RunState::Waiter(waiter) => {
78                if waiter.is_valid() {
79                    TaskStateCode::Sleeping
80                } else {
81                    TaskStateCode::Running
82                }
83            }
84            RunState::Event(_) | RunState::Frozen(_) => TaskStateCode::Sleeping,
85            // TODO(https://fxbug.dev/566829060): Job-control stops currently report
86            // `TaskStateCode::TracingStop` ('t'). Distinguish them to report
87            // `TaskStateCode::Stopped` ('T').
88            RunState::TracingStopped => TaskStateCode::TracingStop,
89        }
90    }
91}
92
93impl PartialEq<RunState> for RunState {
94    fn eq(&self, other: &RunState) -> bool {
95        match (self, other) {
96            (RunState::Running, RunState::Running) => true,
97            (RunState::Waiter(lhs), RunState::Waiter(rhs)) => lhs == rhs,
98            (RunState::Event(lhs), RunState::Event(rhs)) => Arc::ptr_eq(lhs, rhs),
99            (RunState::Frozen(lhs), RunState::Frozen(rhs)) => lhs == rhs,
100            (RunState::TracingStopped, RunState::TracingStopped) => true,
101            _ => false,
102        }
103    }
104}