Skip to main content

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, SharedFsContext};
8use fuchsia_rcu::RcuArc;
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: RcuArc<MemoryManager>,
35
36    /// The file system context for this task.
37    ///
38    /// Holds a reference to the task's [`FsContext`] while the task is running, and is cleared upon
39    /// exit so that the [`FsContext`] (and possibly the whole mount namespace) is released on the
40    /// exiting thread rather than by whichever thread happens to drop the last reference to this
41    /// [`TaskRunningState`].
42    pub(crate) fs: SharedFsContext,
43
44    /// The namespace for abstract AF_UNIX sockets for this task.
45    pub abstract_socket_namespace: Arc<AbstractUnixSocketNamespace>,
46
47    /// The namespace for AF_VSOCK for this task.
48    pub abstract_vsock_namespace: Arc<AbstractVsockSocketNamespace>,
49
50    /// The pid directory, so it doesn't have to be generated and thrown away on every access.
51    /// See https://fxbug.dev/291962828 for details.
52    pub proc_pid_directory_cache: OnceLock<FsNodeHandle>,
53}
54
55impl TaskRunningState {
56    #[track_caller]
57    pub fn files(&self) -> Result<Arc<FdTable>, Errno> {
58        self.files.lock().as_ref().map(|files| files.table.clone()).ok_or_else(|| errno!(ESRCH))
59    }
60
61    pub fn fork_files(&self) -> Option<SharedFdTable> {
62        self.files.lock().as_ref().map(|files| SharedFdTable::new(files.fork()))
63    }
64
65    pub fn share_files(&self) -> Option<SharedFdTable> {
66        self.files.lock().as_ref().map(|files| files.clone())
67    }
68
69    /// Unshares the file descriptor table for this task, if shared.
70    ///
71    /// Updates the [`Arc<FdTable>`] reference in both [`SharedFdTable`] and [`CurrentTask`].
72    pub fn unshare_files(&self, current_task: &CurrentTask) {
73        if let Some(ref mut files) = *self.files.lock() {
74            files.unshare();
75            *current_task.files.borrow_mut() = Some(files.table.clone());
76        }
77    }
78
79    pub fn mm(&self) -> Result<Arc<MemoryManager>, Errno> {
80        self.mm.upgrade().ok_or_else(|| errno!(EINVAL))
81    }
82
83    /// Returns the file system context for this task.
84    ///
85    /// # Errors
86    ///
87    /// Returns [`Err(ESRCH)`] if the task has exited and released its file system context.
88    pub fn fs(&self) -> Result<Arc<FsContext>, Errno> {
89        self.fs.upgrade().ok_or_else(|| errno!(ESRCH))
90    }
91}
92
93/// A synchronized container for a Zircon thread and its cached KOID.
94#[derive(Debug, Clone)]
95pub struct ZirconThread {
96    /// The underlying Zircon thread.
97    ///
98    /// # Thread Safety
99    ///
100    /// Blocking operations are unsafe while holding RCU read locks. However, references to this
101    /// thread must be held across blocking operations (e.g., futex waits). The [`ZirconThread`]
102    /// container as a whole is guarded by RCU because it is a member of the RCU-guarded
103    /// [`TaskRunningState`]. This field is reference counted so it can be accessed outside of RCU
104    /// locks through a strong reference.
105    ///
106    /// Holding a reference to the thread does not guarantee that the task to which it belongs will
107    /// continue running. The task may exit at any time. The thread will continue to exist in memory
108    /// until all references are dropped. When the task exits and execution stops, reference holders
109    /// will observe the thread transition to [`zx::ThreadState::Dead`] normally.
110    pub thread: Arc<zx::Thread>,
111    pub koid: zx::Koid,
112}
113
114impl ZirconThread {
115    pub fn new(thread: Arc<zx::Thread>) -> Self {
116        let koid = thread.koid().expect("Failed to get thread koid");
117        Self { thread, koid }
118    }
119}
120
121impl Deref for ZirconThread {
122    type Target = Arc<zx::Thread>;
123    fn deref(&self) -> &Self::Target {
124        &self.thread
125    }
126}