diff --git a/kernel/src/fs/procfs/pid/mod.rs b/kernel/src/fs/procfs/pid/mod.rs index f6f3d3c63..3cb5e78a2 100644 --- a/kernel/src/fs/procfs/pid/mod.rs +++ b/kernel/src/fs/procfs/pid/mod.rs @@ -1,6 +1,8 @@ // SPDX-License-Identifier: MPL-2.0 -use self::{cmdline::CmdlineFileOps, comm::CommFileOps, exe::ExeSymOps, fd::FdDirOps}; +use self::{ + cmdline::CmdlineFileOps, comm::CommFileOps, exe::ExeSymOps, fd::FdDirOps, task::TaskDirOps, +}; use super::template::{DirOps, ProcDir, ProcDirBuilder}; use crate::{ events::Observer, @@ -18,6 +20,7 @@ mod exe; mod fd; mod stat; mod status; +mod task; /// Represents the inode at `/proc/[pid]`. pub struct PidDirOps(Arc); @@ -56,6 +59,7 @@ impl DirOps for PidDirOps { "cmdline" => CmdlineFileOps::new_inode(self.0.clone(), this_ptr.clone()), "status" => status::StatusFileOps::new_inode(self.0.clone(), this_ptr.clone()), "stat" => stat::StatFileOps::new_inode(self.0.clone(), this_ptr.clone()), + "task" => TaskDirOps::new_inode(self.0.clone(), this_ptr.clone()), _ => return_errno!(Errno::ENOENT), }; Ok(inode) @@ -85,5 +89,8 @@ impl DirOps for PidDirOps { cached_children.put_entry_if_not_found("stat", || { stat::StatFileOps::new_inode(self.0.clone(), this_ptr.clone()) }); + cached_children.put_entry_if_not_found("task", || { + TaskDirOps::new_inode(self.0.clone(), this_ptr.clone()) + }); } } diff --git a/kernel/src/fs/procfs/pid/task.rs b/kernel/src/fs/procfs/pid/task.rs new file mode 100644 index 000000000..9a4be525c --- /dev/null +++ b/kernel/src/fs/procfs/pid/task.rs @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: MPL-2.0 + +use alloc::format; + +use super::*; +use crate::{ + fs::{ + procfs::template::{DirOps, ProcDir, ProcDirBuilder}, + utils::{DirEntryVecExt, Inode}, + }, + process::posix_thread::AsPosixThread, + Process, +}; + +/// Represents the inode at `/proc/[pid]/task`. +pub struct TaskDirOps(Arc); + +impl TaskDirOps { + pub fn new_inode(process_ref: Arc, parent: Weak) -> Arc { + ProcDirBuilder::new(Self(process_ref)) + .parent(parent) + .build() + .unwrap() + } +} + +/// Represents the inode at `/proc/[pid]/task/[tid]`. +struct ThreadDirOps(Arc); + +impl ThreadDirOps { + pub fn new_inode(process_ref: Arc, parent: Weak) -> Arc { + ProcDirBuilder::new(Self(process_ref)) + .parent(parent) + .build() + .unwrap() + } +} + +impl DirOps for ThreadDirOps { + fn lookup_child(&self, this_ptr: Weak, name: &str) -> Result> { + let inode = match name { + "fd" => FdDirOps::new_inode(self.0.clone(), this_ptr.clone()), + _ => return_errno!(Errno::ENOENT), + }; + Ok(inode) + } + + fn populate_children(&self, this_ptr: Weak) { + let this = { + let this = this_ptr.upgrade().unwrap(); + this.downcast_ref::>().unwrap().this() + }; + let mut cached_children = this.cached_children().write(); + cached_children.put_entry_if_not_found("fd", || { + FdDirOps::new_inode(self.0.clone(), this_ptr.clone()) + }); + } +} + +impl DirOps for TaskDirOps { + fn lookup_child(&self, this_ptr: Weak, name: &str) -> Result> { + for task in self.0.tasks().lock().iter() { + if task.as_posix_thread().unwrap().tid() != name.parse::().unwrap() { + continue; + } + return Ok(ThreadDirOps::new_inode(self.0.clone(), this_ptr)); + } + return_errno_with_message!(Errno::ENOENT, "No such thread") + } + + fn populate_children(&self, this_ptr: Weak) { + let this = { + let this = this_ptr.upgrade().unwrap(); + this.downcast_ref::>().unwrap().this() + }; + let mut cached_children = this.cached_children().write(); + for task in self.0.tasks().lock().iter() { + cached_children.put_entry_if_not_found( + &format!("{}", task.as_posix_thread().unwrap().tid()), + || ThreadDirOps::new_inode(self.0.clone(), this_ptr.clone()), + ); + } + } +}