sysutils: add thread display to ps

This commit is contained in:
Mark Poliakov 2025-03-02 14:04:29 +02:00
parent 6f8fce3388
commit 59b34fb269
5 changed files with 148 additions and 24 deletions

View File

@ -135,7 +135,8 @@ impl Process {
io: IrqSafeSpinlock::new(ProcessIo::new()),
});
*process.sysfs_node.write() = Some(add_sysfs_node(&process));
let sysfs_node = add_sysfs_node(&process);
*process.sysfs_node.write() = Some(sysfs_node.clone());
// Add a child if parent specified
if let Some(parent) = parent {
@ -144,6 +145,7 @@ impl Process {
// Create "main" thread
let thread = Thread::new_uthread(process.id, Some(name), info.space, info.context);
thread.add_sysfs_node(&sysfs_node);
process.inner.write().register_thread(thread.clone());
MANAGER.register_process(process.clone());
@ -218,6 +220,9 @@ impl Process {
let thread = Thread::new_uthread(self.id, None, space.clone(), context);
let id = thread.id;
if let Some(sysfs_node) = self.sysfs_node.read().as_ref() {
thread.add_sysfs_node(&sysfs_node);
}
inner.register_thread(thread.clone());
thread.enqueue();

View File

@ -9,6 +9,7 @@ use core::{
use alloc::{
collections::BTreeMap,
format,
string::String,
sync::{Arc, Weak},
};
@ -36,6 +37,10 @@ use yggdrasil_abi::{
};
use crate::{
fs::sysfs::{
attribute::{StringAttribute, StringAttributeOps},
object::KObject,
},
task::{
mem::ForeignPointer,
sched::CpuQueue,
@ -95,6 +100,7 @@ pub struct Thread {
// inner: IrqSafeSpinlock<ThreadInner>,
info: IrqSafeRwLock<ThreadInfo>,
signal_queue: SegQueue<Signal>,
sysfs_node: IrqSafeRwLock<Option<Arc<KObject<Weak<Thread>>>>>,
pub events: ThreadEvents,
pub kill: BoolEvent,
@ -154,6 +160,7 @@ impl Thread {
signal_queue: SegQueue::new(),
events: ThreadEvents::new(),
kill: BoolEvent::new(),
sysfs_node: IrqSafeRwLock::new(None),
affinity: ThreadAffinity::any_cpu(),
});
@ -453,6 +460,18 @@ impl Thread {
self.enqueue();
}
fn cleanup(&self) {
// Can detach debugger now
{
let mut debug = self.debug.lock();
debug.tracer = None;
debug.single_step = false;
self.trace_flags.store(0, Ordering::Release);
}
self.drop_sysfs_node();
}
/// Returns the current thread on the CPU.
///
/// # Panics
@ -591,6 +610,40 @@ impl Thread {
}
}
}
// sysfs operations
pub(super) fn add_sysfs_node(self: &Arc<Self>, parent: &Arc<KObject<Weak<Process>>>) {
let ThreadId::User(id) = self.id else {
return;
};
struct Name;
impl StringAttributeOps for Name {
type Data = Weak<Thread>;
const NAME: &'static str = "name";
fn read(state: &Self::Data) -> Result<String, Error> {
let thread = state.upgrade().ok_or(Error::ProcessNotFound)?;
let name = thread.name.read();
Ok(name.clone())
}
}
let object = KObject::new(Arc::downgrade(self));
object.add_attribute(StringAttribute::from(Name)).ok();
parent.add_object(format!("{id}"), object.clone()).ok();
*self.sysfs_node.write() = Some(object);
}
fn drop_sysfs_node(&self) {
if let Some(node) = self.sysfs_node.write().take() {
node.unlink();
}
}
}
impl GlobalThreadList {
@ -672,13 +725,7 @@ impl CurrentThread {
/// Terminate the current thread
pub fn exit(&self, code: ExitCode) -> ! {
// Can detach debugger now
{
let mut debug = self.debug.lock();
debug.tracer = None;
debug.single_step = false;
self.trace_flags.store(0, Ordering::Release);
}
self.cleanup();
if let Some(process) = self.try_get_process() {
process.handle_thread_exit(self.id, code);

View File

@ -249,6 +249,7 @@ impl<R> ThreadHandle<R> {
}
}
Err(Error::Interrupted) => continue,
Err(Error::ProcessNotFound) => (),
Err(error) => panic!("wait_thread syscall returned error: {error:?}"),
}
return self.into_result();

View File

@ -1,14 +1,33 @@
use std::{fs, io, path::PathBuf, process::ExitCode};
use std::{
fs, io,
path::{Path, PathBuf},
process::ExitCode,
};
use clap::Parser;
#[derive(Debug, Parser)]
struct Args {
#[clap(short, long, help = "Display threads of processes")]
threads: bool,
}
#[derive(Debug)]
struct ThreadInfo {
tid: u32,
name: String,
}
#[derive(Debug)]
struct ProcessInfo {
pid: u32,
name: String,
threads: Vec<ThreadInfo>,
}
fn list_processes() -> io::Result<Vec<u32>> {
fn list_ids<P: AsRef<Path>>(path: P) -> io::Result<Vec<u32>> {
let mut list = vec![];
for entry in fs::read_dir("/sys/proc")? {
for entry in fs::read_dir(path)? {
let Ok(entry) = entry else {
continue;
};
@ -24,33 +43,67 @@ fn list_processes() -> io::Result<Vec<u32>> {
Ok(list)
}
fn process_info(pid: u32) -> io::Result<ProcessInfo> {
fn process_info(pid: u32, args: &Args) -> io::Result<ProcessInfo> {
let base = PathBuf::from("/sys/proc").join(format!("{pid}"));
let name = fs::read_to_string(base.join("name"))?;
Ok(ProcessInfo { pid, name })
let threads = if args.threads {
threads(base).unwrap_or_default()
} else {
vec![]
};
Ok(ProcessInfo { pid, name, threads })
}
fn processes() -> io::Result<Vec<ProcessInfo>> {
let pids = list_processes()?;
fn thread_info<P: AsRef<Path>>(pid_path: P, tid: u32) -> io::Result<ThreadInfo> {
let base = pid_path.as_ref().join(format!("{tid}"));
let name = fs::read_to_string(base.join("name"))?;
Ok(ThreadInfo { tid, name })
}
fn threads<P: AsRef<Path>>(pid_path: P) -> io::Result<Vec<ThreadInfo>> {
let pid_path = pid_path.as_ref();
let tids = list_ids(pid_path)?;
let threads = tids
.into_iter()
.filter_map(|tid| thread_info(pid_path, tid).ok())
.collect();
Ok(threads)
}
fn processes(args: &Args) -> io::Result<Vec<ProcessInfo>> {
let pids = list_ids("/sys/proc")?;
let processes = pids
.into_iter()
.filter_map(|pid| process_info(pid).ok())
.filter_map(|pid| process_info(pid, args).ok())
.collect();
Ok(processes)
}
fn run() -> io::Result<()> {
let mut processes = processes()?;
fn run(args: &Args) -> io::Result<()> {
let mut processes = processes(args)?;
processes.sort_by(|a, b| Ord::cmp(&a.pid, &b.pid));
println!("{:>4} NAME", "PID");
for process in processes {
println!("{:4} {}", process.pid, process.name.trim());
if args.threads {
println!("{:>4} {:>4} NAME", "PID", "TID");
for process in processes {
println!("{:4} {:4} {}", process.pid, "", process.name.trim());
let count = process.threads.len();
for (i, thread) in process.threads.into_iter().enumerate() {
let ch = if i == count - 1 { '└' } else { '├' };
println!("{:>4} {:4} {}", ch, thread.tid, thread.name.trim());
}
}
} else {
println!("{:>4} NAME", "PID");
for process in processes {
println!("{:4} {}", process.pid, process.name.trim());
}
}
Ok(())
}
fn main() -> ExitCode {
match run() {
let args = Args::parse();
match run(&args) {
Ok(()) => ExitCode::SUCCESS,
Err(error) => {
eprintln!("{error}");

View File

@ -1,5 +1,23 @@
use std::{thread, time::Duration};
fn main() {
for i in 0..8 {
println!("\x1B[3{i}mHello\x1B[1molleH\x1B[0m");
let mut threads = vec![];
for i in 0..4 {
let jh = thread::Builder::new()
.name(format!("tst-thread-{i}"))
.spawn(move || {
let current = thread::current();
for _ in 0..10 {
println!("Hi from thread {:?}", current.name());
thread::sleep(Duration::from_secs(1));
}
})
.unwrap();
threads.push(jh);
}
for thread in threads.into_iter() {
thread.join().unwrap();
}
}