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()),
|
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
|
// Add a child if parent specified
|
||||||
if let Some(parent) = parent {
|
if let Some(parent) = parent {
|
||||||
@ -144,6 +145,7 @@ impl Process {
|
|||||||
|
|
||||||
// Create "main" thread
|
// Create "main" thread
|
||||||
let thread = Thread::new_uthread(process.id, Some(name), info.space, info.context);
|
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());
|
process.inner.write().register_thread(thread.clone());
|
||||||
|
|
||||||
MANAGER.register_process(process.clone());
|
MANAGER.register_process(process.clone());
|
||||||
@ -218,6 +220,9 @@ impl Process {
|
|||||||
let thread = Thread::new_uthread(self.id, None, space.clone(), context);
|
let thread = Thread::new_uthread(self.id, None, space.clone(), context);
|
||||||
let id = thread.id;
|
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());
|
inner.register_thread(thread.clone());
|
||||||
|
|
||||||
thread.enqueue();
|
thread.enqueue();
|
||||||
|
@ -9,6 +9,7 @@ use core::{
|
|||||||
|
|
||||||
use alloc::{
|
use alloc::{
|
||||||
collections::BTreeMap,
|
collections::BTreeMap,
|
||||||
|
format,
|
||||||
string::String,
|
string::String,
|
||||||
sync::{Arc, Weak},
|
sync::{Arc, Weak},
|
||||||
};
|
};
|
||||||
@ -36,6 +37,10 @@ use yggdrasil_abi::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
fs::sysfs::{
|
||||||
|
attribute::{StringAttribute, StringAttributeOps},
|
||||||
|
object::KObject,
|
||||||
|
},
|
||||||
task::{
|
task::{
|
||||||
mem::ForeignPointer,
|
mem::ForeignPointer,
|
||||||
sched::CpuQueue,
|
sched::CpuQueue,
|
||||||
@ -95,6 +100,7 @@ pub struct Thread {
|
|||||||
// inner: IrqSafeSpinlock<ThreadInner>,
|
// inner: IrqSafeSpinlock<ThreadInner>,
|
||||||
info: IrqSafeRwLock<ThreadInfo>,
|
info: IrqSafeRwLock<ThreadInfo>,
|
||||||
signal_queue: SegQueue<Signal>,
|
signal_queue: SegQueue<Signal>,
|
||||||
|
sysfs_node: IrqSafeRwLock<Option<Arc<KObject<Weak<Thread>>>>>,
|
||||||
|
|
||||||
pub events: ThreadEvents,
|
pub events: ThreadEvents,
|
||||||
pub kill: BoolEvent,
|
pub kill: BoolEvent,
|
||||||
@ -154,6 +160,7 @@ impl Thread {
|
|||||||
signal_queue: SegQueue::new(),
|
signal_queue: SegQueue::new(),
|
||||||
events: ThreadEvents::new(),
|
events: ThreadEvents::new(),
|
||||||
kill: BoolEvent::new(),
|
kill: BoolEvent::new(),
|
||||||
|
sysfs_node: IrqSafeRwLock::new(None),
|
||||||
|
|
||||||
affinity: ThreadAffinity::any_cpu(),
|
affinity: ThreadAffinity::any_cpu(),
|
||||||
});
|
});
|
||||||
@ -453,6 +460,18 @@ impl Thread {
|
|||||||
self.enqueue();
|
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.
|
/// Returns the current thread on the CPU.
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # 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 {
|
impl GlobalThreadList {
|
||||||
@ -672,13 +725,7 @@ impl CurrentThread {
|
|||||||
|
|
||||||
/// Terminate the current thread
|
/// Terminate the current thread
|
||||||
pub fn exit(&self, code: ExitCode) -> ! {
|
pub fn exit(&self, code: ExitCode) -> ! {
|
||||||
// Can detach debugger now
|
self.cleanup();
|
||||||
{
|
|
||||||
let mut debug = self.debug.lock();
|
|
||||||
debug.tracer = None;
|
|
||||||
debug.single_step = false;
|
|
||||||
self.trace_flags.store(0, Ordering::Release);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(process) = self.try_get_process() {
|
if let Some(process) = self.try_get_process() {
|
||||||
process.handle_thread_exit(self.id, code);
|
process.handle_thread_exit(self.id, code);
|
||||||
|
@ -249,6 +249,7 @@ impl<R> ThreadHandle<R> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(Error::Interrupted) => continue,
|
Err(Error::Interrupted) => continue,
|
||||||
|
Err(Error::ProcessNotFound) => (),
|
||||||
Err(error) => panic!("wait_thread syscall returned error: {error:?}"),
|
Err(error) => panic!("wait_thread syscall returned error: {error:?}"),
|
||||||
}
|
}
|
||||||
return self.into_result();
|
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)]
|
#[derive(Debug)]
|
||||||
struct ProcessInfo {
|
struct ProcessInfo {
|
||||||
pid: u32,
|
pid: u32,
|
||||||
name: String,
|
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![];
|
let mut list = vec![];
|
||||||
for entry in fs::read_dir("/sys/proc")? {
|
for entry in fs::read_dir(path)? {
|
||||||
let Ok(entry) = entry else {
|
let Ok(entry) = entry else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
@ -24,33 +43,67 @@ fn list_processes() -> io::Result<Vec<u32>> {
|
|||||||
Ok(list)
|
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 base = PathBuf::from("/sys/proc").join(format!("{pid}"));
|
||||||
let name = fs::read_to_string(base.join("name"))?;
|
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>> {
|
fn thread_info<P: AsRef<Path>>(pid_path: P, tid: u32) -> io::Result<ThreadInfo> {
|
||||||
let pids = list_processes()?;
|
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
|
let processes = pids
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|pid| process_info(pid).ok())
|
.filter_map(|pid| process_info(pid, args).ok())
|
||||||
.collect();
|
.collect();
|
||||||
Ok(processes)
|
Ok(processes)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run() -> io::Result<()> {
|
fn run(args: &Args) -> io::Result<()> {
|
||||||
let mut processes = processes()?;
|
let mut processes = processes(args)?;
|
||||||
processes.sort_by(|a, b| Ord::cmp(&a.pid, &b.pid));
|
processes.sort_by(|a, b| Ord::cmp(&a.pid, &b.pid));
|
||||||
println!("{:>4} NAME", "PID");
|
if args.threads {
|
||||||
for process in processes {
|
println!("{:>4} {:>4} NAME", "PID", "TID");
|
||||||
println!("{:4} {}", process.pid, process.name.trim());
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> ExitCode {
|
fn main() -> ExitCode {
|
||||||
match run() {
|
let args = Args::parse();
|
||||||
|
match run(&args) {
|
||||||
Ok(()) => ExitCode::SUCCESS,
|
Ok(()) => ExitCode::SUCCESS,
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
eprintln!("{error}");
|
eprintln!("{error}");
|
||||||
|
@ -1,5 +1,23 @@
|
|||||||
|
use std::{thread, time::Duration};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
for i in 0..8 {
|
let mut threads = vec![];
|
||||||
println!("\x1B[3{i}mHello\x1B[1molleH\x1B[0m");
|
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