diff --git a/src/percpu.rs b/src/percpu.rs index d7fd1dc6e7..0395afc393 100644 --- a/src/percpu.rs +++ b/src/percpu.rs @@ -13,11 +13,13 @@ use syscall::PtraceFlags; use crate::{ arch::device::ArchPercpuMisc, - context::{empty_cr3, memory::AddrSpaceWrapper, switch::ContextSwitchPercpu, ContextRef}, + context::{ + empty_cr3, memory::AddrSpaceWrapper, switch::ContextSwitchPercpu, ContextLock, ContextRef, + }, cpu_set::{LogicalCpuId, MAX_CPU_COUNT}, cpu_stats::{CpuStats, CpuStatsData}, ptrace::Session, - sync::{CleanLockToken, RwLock, L1}, + sync::{CleanLockToken, LockToken, RwLock, L0, L1}, syscall::debug::SyscallDebugInfo, }; @@ -70,6 +72,20 @@ pub fn get_all_stats() -> Vec<(LogicalCpuId, CpuStatsData)> { res } +/// Get copy of all cpu ref contexts +pub fn get_all_contexts(mut token: LockToken<'_, L1>) -> Vec> { + let mut all_contexts = Vec::new(); + for block in ALL_PERCPU_BLOCKS + .iter() + .filter_map(|block| unsafe { block.load(Ordering::Relaxed).as_ref() }) + { + // TODO: Lock token violation, downgrade this to L2 later + let contexts = unsafe { &block.contexts.reupgradeable_read(token.token()) }; + all_contexts.extend(contexts.iter().filter_map(|x| x.upgrade())); + } + all_contexts +} + // PercpuBlock::current() is implemented somewhere in the arch-specific modules pub fn shootdown_tlb_ipi(target: Option) { diff --git a/src/scheme/sys/block.rs b/src/scheme/sys/block.rs index ef5b132730..1a9d59859e 100644 --- a/src/scheme/sys/block.rs +++ b/src/scheme/sys/block.rs @@ -1,7 +1,7 @@ use alloc::{string::String, vec::Vec}; use core::fmt::Write; -use crate::{context, sync::CleanLockToken, syscall::error::Result}; +use crate::{context, percpu, sync::CleanLockToken, syscall::error::Result}; pub fn resource(token: &mut CleanLockToken) -> Result> { let mut string = String::new(); @@ -9,9 +9,8 @@ pub fn resource(token: &mut CleanLockToken) -> Result> { { let mut rows = Vec::new(); { - let mut contexts = context::contexts(token.token()); - let (contexts, mut token) = contexts.token_split(); - for context_lock in contexts.iter().filter_map(|r| r.upgrade()) { + let contexts = percpu::get_all_contexts(token.downgrade()); + for context_lock in contexts { let context = context_lock.read(token.token()); rows.push((context.pid, context.name, context.status_reason)); } diff --git a/src/scheme/sys/context.rs b/src/scheme/sys/context.rs index 644b847c29..ab09af2b3d 100644 --- a/src/scheme/sys/context.rs +++ b/src/scheme/sys/context.rs @@ -5,7 +5,7 @@ use alloc::{ }; use core::fmt::Write; -use crate::{context, sync::CleanLockToken, syscall::error::Result}; +use crate::{context, percpu, sync::CleanLockToken, syscall::error::Result}; pub fn resource(token: &mut CleanLockToken) -> Result> { let mut string = format!( @@ -15,32 +15,59 @@ pub fn resource(token: &mut CleanLockToken) -> Result> { let mut rows = Vec::new(); { - let mut contexts = context::contexts(token.token()); - let (contexts, mut token) = contexts.token_split(); - for context_ref in contexts.iter().filter_map(|r| r.upgrade()) { + let mut contexts = percpu::get_all_contexts(token.downgrade()); + for context_ref in contexts { let context = context_ref.read(token.token()); + let addr_space = context.addr_space().map(|a| a.clone()); + + let affinity = context.sched_affinity.to_string(); + let cpu_time_s = context.cpu_time / crate::time::NANOS_PER_SEC; + let cpu_time_ns = context.cpu_time % crate::time::NANOS_PER_SEC; + let mut memory = context.kfx.len(); + if let Some(ref kstack) = context.kstack { + memory += kstack.len(); + } + let (status, cpuid) = (context.status.clone(), context.cpu_id); + let (pid, euid, egid) = (context.pid, context.euid, context.egid); + let (running, is_awake) = (context.running, context.wake.is_some()); + let name = context.name; + drop(context); + + let heap = match addr_space { + Ok(addr_space) => { + let addr_space_guard = addr_space.acquire_read(token.downgrade()); + let mut memory = 0; + // TODO: All user programs must have some grant in order for executable memory to even + // exist, but is this a good indicator of whether it is user or kernel? + let is_kernel = addr_space_guard.grants.is_empty(); + for (_base, info) in addr_space_guard.grants.iter() { + // TODO: shared memory? wrap as method? + if matches!(info.provider, context::memory::Provider::Allocated { .. }) { + memory += info.page_count() * crate::memory::PAGE_SIZE; + } + } + Some((memory, is_kernel)) + } + Err(_) => None, + }; let mut stat_string = String::new(); - // TODO: All user programs must have some grant in order for executable memory to even - // exist, but is this a good indicator of whether it is user or kernel? - stat_string.push(match context.addr_space() { - Ok(addr_space) => { - // TODO: Commented out due Lock ordering violation - // if addr_space.acquire_read(token.downgrade()).grants.is_empty() { - // 'K' - // } else { - // 'U' - // } - 'U' + stat_string.push(match heap { + Some((pages, is_kernel)) => { + if is_kernel { + 'K' + } else { + 'U' + } } _ => 'R', }); - match context.status { + match status { context::Status::Runnable => { stat_string.push('R'); } context::Status::Blocked | context::Status::HardBlocked { .. } => { - if context.wake.is_some() { + if is_awake { stat_string.push('S'); } else { stat_string.push('B'); @@ -50,20 +77,16 @@ pub fn resource(token: &mut CleanLockToken) -> Result> { stat_string.push('Z'); } } - if context.running { + if running { stat_string.push('+'); } - let cpu_string = match context.cpu_id { + let cpu_string = match cpuid { Some(cpu_id) => { format!("{cpu_id}") } _ => "?".to_owned(), }; - let affinity = context.sched_affinity.to_string(); - - let cpu_time_s = context.cpu_time / crate::time::NANOS_PER_SEC; - let cpu_time_ns = context.cpu_time % crate::time::NANOS_PER_SEC; let cpu_time_string = format!( "{:02}:{:02}:{:02}.{:02}", cpu_time_s / 3600, @@ -72,21 +95,9 @@ pub fn resource(token: &mut CleanLockToken) -> Result> { cpu_time_ns / 10_000_000 ); - let mut memory = context.kfx.len(); - if let Some(ref kstack) = context.kstack { - memory += kstack.len(); + if let Some((heap, _)) = heap { + memory += heap; } - // TODO: Commented out due Lock ordering violation - /* - if let Ok(addr_space) = context.addr_space() { - for (_base, info) in addr_space.acquire_read(token.downgrade()).grants.iter() { - // TODO: method - if matches!(info.provider, context::memory::Provider::Allocated { .. }) { - memory += info.page_count() * PAGE_SIZE; - } - } - } - */ let memory_string = if memory >= 1024 * 1024 * 1024 { format!("{} GB", memory / 1024 / 1024 / 1024) @@ -99,15 +110,15 @@ pub fn resource(token: &mut CleanLockToken) -> Result> { }; rows.push(( - context.pid, - context.euid, - context.egid, + pid, + euid, + egid, stat_string, cpu_string, affinity, cpu_time_string, memory_string, - context.name, + name, )); } } diff --git a/src/scheme/sys/iostat.rs b/src/scheme/sys/iostat.rs index 9d9cd2cae0..0d6a76fbd5 100644 --- a/src/scheme/sys/iostat.rs +++ b/src/scheme/sys/iostat.rs @@ -4,7 +4,7 @@ use crate::{ memory::{Grant, PageSpan}, }, memory::PAGE_SIZE, - scheme, + percpu, scheme, sync::CleanLockToken, syscall::{ error::Result, @@ -22,9 +22,7 @@ fn inner(fpath_user: UserSliceRw, token: &mut CleanLockToken) -> Result> { let mut rows = Vec::new(); { - let mut contexts = context::contexts(token.token()); - let (contexts, mut token) = contexts.token_split(); - for context_ref in contexts.iter().filter_map(|r| r.upgrade()) { + for context_ref in percpu::get_all_contexts(token.downgrade()) { let mut current = context_ref.read(token.token()); let (context, mut token) = current.token_split(); rows.push(( diff --git a/src/scheme/sys/stat.rs b/src/scheme/sys/stat.rs index 69f37b3b82..a5b6b1b971 100644 --- a/src/scheme/sys/stat.rs +++ b/src/scheme/sys/stat.rs @@ -1,9 +1,9 @@ use core::fmt::Write as _; use crate::{ - context::{contexts, ContextRef, Status}, + context::{ContextRef, Status}, cpu_stats::{get_context_switch_count, get_contexts_count, irq_counts}, - percpu::get_all_stats, + percpu::{self, get_all_stats}, sync::CleanLockToken, syscall::error::Result, time::START, @@ -76,11 +76,8 @@ fn get_contexts_stats(token: &mut CleanLockToken) -> (u64, u64) { let mut running = 0; let mut blocked = 0; - let mut contexts = contexts(token.token()); - let (contexts, mut token) = contexts.token_split(); - let statuses = contexts + let statuses = percpu::get_all_contexts(token.downgrade()) .iter() - .filter_map(ContextRef::upgrade) .map(|context| context.read(token.token()).status.clone()) .collect::>(); diff --git a/src/scheme/sys/syscall.rs b/src/scheme/sys/syscall.rs index 8a72b9bcb0..1d49d53e21 100644 --- a/src/scheme/sys/syscall.rs +++ b/src/scheme/sys/syscall.rs @@ -1,7 +1,11 @@ use alloc::{string::String, vec::Vec}; use core::fmt::Write; -use crate::{context, sync::CleanLockToken, syscall, syscall::error::Result}; +use crate::{ + context, percpu, + sync::CleanLockToken, + syscall::{self, error::Result}, +}; pub fn resource(token: &mut CleanLockToken) -> Result> { let mut string = String::new(); @@ -9,9 +13,7 @@ pub fn resource(token: &mut CleanLockToken) -> Result> { { let mut rows = Vec::new(); { - let mut contexts = context::contexts(token.token()); - let (contexts, mut token) = contexts.token_split(); - for context_ref in contexts.iter().filter_map(|r| r.upgrade()) { + for context_ref in percpu::get_all_contexts(token.downgrade()) { let context = context_ref.read(token.token()); rows.push((context.pid, context.name, context.current_syscall())); }