starnix_core/task/task_running_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::mm::MemoryManager;
6use crate::task::{AbstractUnixSocketNamespace, AbstractVsockSocketNamespace, CurrentTask};
7use crate::vfs::{FdTable, FsContext, FsNodeHandle, SharedFdTable};
8use fuchsia_rcu::{RcuArc, RcuOptionArc, RcuOptionBox};
9use starnix_sync::{LockDepMutex, TaskFilesLock};
10use starnix_uapi::errno;
11use starnix_uapi::errors::Errno;
12use std::ops::Deref;
13use std::sync::{Arc, OnceLock};
14
15/// The running state of a task.
16///
17/// This structure contains the state of a task that is only relevant while the task is running. It
18/// is dropped when the task enters an exited state.
19pub struct TaskRunningState {
20 /// A handle to the underlying Zircon thread object.
21 ///
22 /// Some tasks lack an underlying Zircon thread. These tasks are used internally by the
23 /// Starnix kernel to track background work, typically on a `kthread`.
24 pub thread: OnceLock<ZirconThread>,
25
26 /// The file descriptor table for this task.
27 ///
28 /// This table can be shared by many tasks.
29 ///
30 /// This is always `Some` while the task is running. It becomes `None` upon exit.
31 pub files: LockDepMutex<Option<SharedFdTable>, TaskFilesLock>,
32
33 /// The memory manager for this task. This is `None` only for system tasks.
34 pub mm: RcuOptionArc<MemoryManager>,
35
36 /// The file system for this task.
37 pub fs: RcuArc<FsContext>,
38
39 /// The namespace for abstract AF_UNIX sockets for this task.
40 pub abstract_socket_namespace: Arc<AbstractUnixSocketNamespace>,
41
42 /// The namespace for AF_VSOCK for this task.
43 pub abstract_vsock_namespace: Arc<AbstractVsockSocketNamespace>,
44
45 /// The pid directory, so it doesn't have to be generated and thrown away on every access.
46 /// See https://fxbug.dev/291962828 for details.
47 pub proc_pid_directory_cache: RcuOptionBox<FsNodeHandle>,
48}
49
50impl TaskRunningState {
51 #[track_caller]
52 pub fn files(&self) -> Result<Arc<FdTable>, Errno> {
53 self.files.lock().as_ref().map(|files| files.table.clone()).ok_or_else(|| errno!(ESRCH))
54 }
55
56 pub fn fork_files(&self) -> Option<SharedFdTable> {
57 self.files.lock().as_ref().map(|files| SharedFdTable::new(files.fork()))
58 }
59
60 pub fn share_files(&self) -> Option<SharedFdTable> {
61 self.files.lock().as_ref().map(|files| files.clone())
62 }
63
64 /// Unshares the file descriptor table for this task, if shared.
65 ///
66 /// Updates the [`Arc<FdTable>`] reference in both [`SharedFdTable`] and [`CurrentTask`].
67 pub fn unshare_files(&self, current_task: &CurrentTask) {
68 if let Some(ref mut files) = *self.files.lock() {
69 files.unshare();
70 *current_task.files.borrow_mut() = Some(files.table.clone());
71 }
72 }
73
74 pub fn mm(&self) -> Result<Arc<MemoryManager>, Errno> {
75 self.mm.to_option_arc().ok_or_else(|| errno!(EINVAL))
76 }
77
78 pub fn fs(&self) -> Arc<FsContext> {
79 self.fs.to_arc()
80 }
81}
82
83/// A synchronized container for a Zircon thread and its cached KOID.
84#[derive(Debug, Clone)]
85pub struct ZirconThread {
86 /// The underlying Zircon thread.
87 ///
88 /// # Thread Safety
89 ///
90 /// Blocking operations are unsafe while holding RCU read locks. However, references to this
91 /// thread must be held across blocking operations (e.g., futex waits). The [`ZirconThread`]
92 /// container as a whole is guarded by RCU because it is a member of the RCU-guarded
93 /// [`TaskRunningState`]. This field is reference counted so it can be accessed outside of RCU
94 /// locks through a strong reference.
95 ///
96 /// Holding a reference to the thread does not guarantee that the task to which it belongs will
97 /// continue running. The task may exit at any time. The thread will continue to exist in memory
98 /// until all references are dropped. When the task exits and execution stops, reference holders
99 /// will observe the thread transition to [`zx::ThreadState::Dead`] normally.
100 pub thread: Arc<zx::Thread>,
101 pub koid: zx::Koid,
102}
103
104impl ZirconThread {
105 pub fn new(thread: Arc<zx::Thread>) -> Self {
106 let koid = thread.koid().expect("Failed to get thread koid");
107 Self { thread, koid }
108 }
109}
110
111impl Deref for ZirconThread {
112 type Target = Arc<zx::Thread>;
113 fn deref(&self) -> &Self::Target {
114 &self.thread
115 }
116}