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}