sysutils: add thread display to ps
This commit is contained in:
parent
6f8fce3388
commit
59b34fb269
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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}");
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user