diff --git a/kernel/src/filesystem/procfs/meminfo.rs b/kernel/src/filesystem/procfs/meminfo.rs index 224457456d..f6294da072 100644 --- a/kernel/src/filesystem/procfs/meminfo.rs +++ b/kernel/src/filesystem/procfs/meminfo.rs @@ -16,8 +16,8 @@ use crate::{ mm::page_cache_stats, }; use alloc::{ - borrow::ToOwned, format, + string::String, sync::{Arc, Weak}, vec::Vec, }; @@ -36,68 +36,52 @@ impl MeminfoFileOps { } fn generate_meminfo_content() -> Vec { - use crate::arch::mm::LockedFrameAllocator; - use crate::arch::MMArch; + use crate::arch::mm::LockedFrameAllocator; + use crate::arch::MMArch; - let usage = unsafe { LockedFrameAllocator.usage() }; - let stats = page_cache_stats::snapshot(); - let page_kb = (MMArch::PAGE_SIZE >> 10) as u64; - let cached_pages = stats.file_pages.saturating_sub(stats.shmem_pages); + let usage = unsafe { LockedFrameAllocator.usage() }; + let stats = page_cache_stats::snapshot(); + let page_kb = (MMArch::PAGE_SIZE >> 10) as u64; - let mut data: Vec = vec![]; + let mem_total_kb = (usage.total().bytes() >> 10) as u64; + let mem_free_kb = (usage.free().bytes() >> 10) as u64; - data.append( - &mut format!("MemTotal:\t{} kB\n", usage.total().bytes() >> 10) - .as_bytes() - .to_owned(), - ); + let cached_pages = stats.file_pages.saturating_sub(stats.shmem_pages); + let cached_kb = cached_pages * page_kb; - data.append( - &mut format!("MemFree:\t{} kB\n", usage.free().bytes() >> 10) - .as_bytes() - .to_owned(), - ); + let dirty_kb = stats.file_dirty * page_kb; + let writeback_kb = stats.file_writeback * page_kb; + let mapped_kb = stats.file_mapped * page_kb; + let shmem_kb = stats.shmem_pages * page_kb; - data.append(&mut format!("Buffers:\t{} kB\n", 0u64).as_bytes().to_owned()); - data.append( - &mut format!("Cached:\t\t{} kB\n", cached_pages * page_kb) - .as_bytes() - .to_owned(), - ); - data.append(&mut format!("SwapTotal:\t{} kB\n", 0u64).as_bytes().to_owned()); - data.append(&mut format!("SwapFree:\t{} kB\n", 0u64).as_bytes().to_owned()); - data.append( - &mut format!("Dirty:\t\t{} kB\n", stats.file_dirty * page_kb) - .as_bytes() - .to_owned(), - ); - data.append( - &mut format!("Writeback:\t{} kB\n", stats.file_writeback * page_kb) - .as_bytes() - .to_owned(), - ); - data.append( - &mut format!("Mapped:\t\t{} kB\n", stats.file_mapped * page_kb) - .as_bytes() - .to_owned(), - ); - data.append( - &mut format!("Shmem:\t\t{} kB\n", stats.shmem_pages * page_kb) - .as_bytes() - .to_owned(), - ); - data.append(&mut format!("Slab:\t\t{} kB\n", 0u64).as_bytes().to_owned()); - data.append( - &mut format!("SReclaimable:\t{} kB\n", 0u64) - .as_bytes() - .to_owned(), - ); - data.append(&mut format!("SUnreclaim:\t{} kB\n", 0u64).as_bytes().to_owned()); + let mem_available_kb = mem_free_kb.saturating_add(cached_kb); - // 去除多余的 \0 并在结尾添加 \0 - trim_string(&mut data); + let mut s = String::new(); - data + macro_rules! push_kb { + ($name:expr, $value:expr) => { + s.push_str(&format!("{:<15}{:>8} kB\n", concat!($name, ":"), $value)); + }; + } + + push_kb!("MemTotal", mem_total_kb); + push_kb!("MemFree", mem_free_kb); + push_kb!("MemAvailable", mem_available_kb); + push_kb!("Buffers", 0u64); + push_kb!("Cached", cached_kb); + push_kb!("SwapTotal", 0u64); + push_kb!("SwapFree", 0u64); + push_kb!("Dirty", dirty_kb); + push_kb!("Writeback", writeback_kb); + push_kb!("Mapped", mapped_kb); + push_kb!("Shmem", shmem_kb); + push_kb!("Slab", 0u64); + push_kb!("SReclaimable", 0u64); + push_kb!("SUnreclaim", 0u64); + + let mut data = s.into_bytes(); + trim_string(&mut data); + data } } diff --git a/kernel/src/filesystem/procfs/mod.rs b/kernel/src/filesystem/procfs/mod.rs index 4c9d0d73b0..3a1ca6ad58 100644 --- a/kernel/src/filesystem/procfs/mod.rs +++ b/kernel/src/filesystem/procfs/mod.rs @@ -15,6 +15,7 @@ mod cpuinfo; pub mod klog; pub mod kmsg; mod kmsg_file; +mod uptime; mod loadavg; mod meminfo; mod mounts; diff --git a/kernel/src/filesystem/procfs/pid/mod.rs b/kernel/src/filesystem/procfs/pid/mod.rs index 1da77b0c42..d44b8366b7 100644 --- a/kernel/src/filesystem/procfs/pid/mod.rs +++ b/kernel/src/filesystem/procfs/pid/mod.rs @@ -164,7 +164,9 @@ impl DirOps for PidDirOps { let cred = pcb.cred(); Some((cred.euid.data(), cred.egid.data())) } - + fn validate_child(&self, _child: &dyn IndexNode) -> bool { + ProcessManager::find(self.pid).is_some() + } fn lookup_child( &self, dir: &ProcDir, diff --git a/kernel/src/filesystem/procfs/pid/stat.rs b/kernel/src/filesystem/procfs/pid/stat.rs index b58b50da51..7482ab7a4b 100644 --- a/kernel/src/filesystem/procfs/pid/stat.rs +++ b/kernel/src/filesystem/procfs/pid/stat.rs @@ -1,7 +1,3 @@ -//! /proc/[pid]/stat - 进程状态信息 -//! -//! 以单行格式返回进程的状态信息,兼容 Linux procfs 格式 - use core::sync::atomic::Ordering; use crate::libs::mutex::MutexGuard; @@ -15,7 +11,7 @@ use crate::{ vfs::{FilePrivateData, IndexNode, InodeMode}, }, mm::MemoryManagementArch, - process::{pid::PidType, ProcessControlBlock, ProcessManager, ProcessState, RawPid}, + process::{ProcessControlBlock, ProcessManager, ProcessState, RawPid}, sched::{cputime::ns_to_clock_t, prio::PrioUtil}, }; use alloc::{ @@ -40,8 +36,15 @@ impl StatFileOps { } } -/// 将进程状态转换为 Linux 风格的字符 -fn state_to_linux_char(state: ProcessState) -> char { +/// 将进程状态转换为 Linux 风格字符 +fn state_to_linux_char(pcb: &ProcessControlBlock, state: ProcessState) -> char { + if pcb.is_dead() { + return 'X'; + } + if pcb.is_zombie() { + return 'Z'; + } + match state { ProcessState::Runnable => 'R', ProcessState::Blocked(interruptable) => { @@ -63,18 +66,42 @@ fn sanitize_comm_for_proc_stat(comm: &str) -> String { .collect() } +/// 统计线程组中的线程数量 +fn thread_count(pcb: &Arc) -> i64 { + let leader = if pcb.is_thread_group_leader() { + pcb.clone() + } else { + pcb.threads_read_irqsave() + .group_leader() + .unwrap_or_else(|| pcb.clone()) + }; + + let ti = leader.threads_read_irqsave(); + let mut cnt = 1i64; + + for weak in ti.group_tasks_clone() { + if let Some(task) = weak.upgrade() { + if !task.is_dead() { + cnt += 1; + } + } + } + + cnt +} + /// 生成 Linux 风格的 /proc/[pid]/stat 行 fn generate_linux_proc_stat_line( pid: RawPid, comm: &str, state: ProcessState, - ppid: RawPid, pcb: &Arc, ) -> String { let comm = sanitize_comm_for_proc_stat(comm); - let state_ch = state_to_linux_char(state); + let state_ch = state_to_linux_char(pcb, state); - // 尽量填真实值;拿不到的先填 0 + // 当前先尽量填真实值;拿不到的保守填 0 + let ppid: usize = pcb.basic().ppid().data(); let pgrp: usize = 0; let session: usize = 0; let tty_nr: i32 = pcb @@ -83,13 +110,14 @@ fn generate_linux_proc_stat_line( .map(|tty| tty.core().device_number().new_encode_dev() as i32) .unwrap_or(0); let tpgid: i32 = 0; - let flags: u64 = 0; + let flags: u64 = pcb.flags().bits() as u64; + let minflt: u64 = 0; let cminflt: u64 = 0; let majflt: u64 = 0; let cmajflt: u64 = 0; - // === 读取真实的 CPU 时间 === + // 真实 CPU 时间 let cpu_time = pcb.cputime(); let utime = ns_to_clock_t(cpu_time.utime.load(Ordering::Relaxed)); let stime = ns_to_clock_t(cpu_time.stime.load(Ordering::Relaxed)); @@ -97,23 +125,20 @@ fn generate_linux_proc_stat_line( let cutime: i64 = 0; let cstime: i64 = 0; - // === 读取真实的 priority 和 nice 值 === + // priority / nice let prio_data = pcb.sched_info().prio_data(); let priority: i64 = prio_data.prio as i64; let nice: i64 = PrioUtil::prio_to_nice(prio_data.static_prio) as i64; drop(prio_data); - // 线程组中的线程数量 - let num_threads: i64 = pcb - .task_pid_ptr(PidType::TGID) - .map(|tgid_pid| tgid_pid.tasks_iter(PidType::TGID).count() as i64) - .unwrap_or(1); + let num_threads: i64 = thread_count(pcb); let itrealvalue: i64 = 0; - // starttime: 进程启动时间(暂时为 0,需要 PCB 添加 start_time 字段) + // 当前还没有可靠的“进程启动时刻 clock ticks”来源,先保守为 0 let starttime: u64 = 0; // vsize: bytes, rss: pages + // 这里 rss 仍是近似值:按 VMA 总大小折算页数,而不是真实驻留页统计 let (vsize_bytes, rss_pages) = pcb .basic() .user_vm() @@ -125,7 +150,7 @@ fn generate_linux_proc_stat_line( }) .unwrap_or((0, 0)); - // processor: 进程最后运行的 CPU ID + // processor: 最后运行的 CPU ID let processor: i32 = pcb .sched_info() .on_cpu() @@ -137,7 +162,6 @@ fn generate_linux_proc_stat_line( {minflt} {cminflt} {majflt} {cmajflt} {utime} {stime} {cutime} {cstime} {priority} {nice} \ {num_threads} {itrealvalue} {starttime} {vsize_bytes} {rss_pages} 0 0 0 0 0 0 0 0 0 0 0 0 0 {processor} 0 0 0 0 0\n", pid = pid.data(), - ppid = ppid.data(), ) } @@ -155,12 +179,7 @@ impl FileOps for StatFileOps { let sched = pcb.sched_info(); let state = sched.inner_lock_read_irqsave().state(); - let ppid = pcb - .parent_pcb() - .map(|p| p.raw_pid()) - .unwrap_or(RawPid::new(0)); - - let content = generate_linux_proc_stat_line(self.pid, &comm, state, ppid, &pcb); + let content = generate_linux_proc_stat_line(self.pid, &comm, state, &pcb); proc_read(offset, len, buf, content.as_bytes()) } -} +} \ No newline at end of file diff --git a/kernel/src/filesystem/procfs/pid/status.rs b/kernel/src/filesystem/procfs/pid/status.rs index 6e64e2da79..0b7af6f849 100644 --- a/kernel/src/filesystem/procfs/pid/status.rs +++ b/kernel/src/filesystem/procfs/pid/status.rs @@ -1,7 +1,3 @@ -//! /proc/[pid]/status - 进程状态信息 -//! -//! 显示进程的详细状态信息 - use crate::libs::mutex::MutexGuard; use crate::{ filesystem::{ @@ -11,12 +7,11 @@ use crate::{ }, vfs::{FilePrivateData, IndexNode, InodeMode}, }, - process::{ProcessManager, RawPid}, + process::{ProcessManager, ProcessState, RawPid}, }; use alloc::{ - borrow::ToOwned, format, - string::ToString, + string::{String, ToString}, sync::{Arc, Weak}, vec::Vec, }; @@ -41,124 +36,148 @@ impl StatusFileOps { .unwrap() } + fn state_to_string(pcb: &crate::process::ProcessControlBlock, state: ProcessState) -> String { + if pcb.is_dead() { + return "Dead".to_string(); + } + if pcb.is_zombie() { + return "Zombie".to_string(); + } + + match state { + ProcessState::Runnable => "Runnable".to_string(), + ProcessState::Blocked(true) => "Blocked(Interruptable)".to_string(), + ProcessState::Blocked(false) => "Blocked(Uninterruptable)".to_string(), + ProcessState::Stopped => "Stopped".to_string(), + ProcessState::Exited(code) => format!("Exited({code})"), + } + } + + fn thread_count(pcb: &Arc) -> usize { + let leader = if pcb.is_thread_group_leader() { + pcb.clone() + } else { + pcb.threads_read_irqsave() + .group_leader() + .unwrap_or_else(|| pcb.clone()) + }; + + let ti = leader.threads_read_irqsave(); + let mut cnt = 1usize; + + for weak in ti.group_tasks_clone() { + if let Some(task) = weak.upgrade() { + if !task.is_dead() { + cnt += 1; + } + } + } + + cnt + } + + fn push_line(buf: &mut String, key: &str, value: impl core::fmt::Display) { + buf.push_str(&format!("{key:<12}: {value}\n")); + } + /// 生成 status 文件内容 fn generate_status_content(&self) -> Result, SystemError> { - // 动态查找进程,确保获取最新状态 let pcb = ProcessManager::find(self.pid).ok_or(SystemError::ESRCH)?; - let mut pdata = Vec::new(); - - // Name - pdata.append( - &mut format!("Name:\t{}", pcb.basic().name()) - .as_bytes() - .to_owned(), - ); - - let sched_info_guard = pcb.sched_info(); - let state = sched_info_guard.inner_lock_read_irqsave().state(); - let cpu_id = sched_info_guard - .on_cpu() - .map(|cpu| cpu.data() as i32) - .unwrap_or(-1); - let priority = sched_info_guard.policy(); - let vrtime = sched_info_guard.sched_entity.vruntime; - let time = sched_info_guard.sched_entity.sum_exec_runtime; - let start_time = sched_info_guard.sched_entity.exec_start; - - // State - pdata.append(&mut format!("\nState:\t{:?}", state).as_bytes().to_owned()); - - // Tgid - pdata.append( - &mut format!( - "\nTgid:\t{}", - pcb.task_tgid_vnr() - .unwrap_or(crate::process::RawPid::new(0)) - .into() - ) - .into(), - ); - - // Pid - pdata.append( - &mut format!("\nPid:\t{}", pcb.task_pid_vnr().data()) - .as_bytes() - .to_owned(), - ); - - // Ppid - pdata.append( - &mut format!( - "\nPpid:\t{}", - pcb.parent_pcb() - .map(|p| p.task_pid_vnr().data() as isize) - .unwrap_or(-1) - ) - .as_bytes() - .to_owned(), - ); - - // FDSize - if matches!(state, crate::process::ProcessState::Exited(_)) { - pdata.append(&mut format!("\nFDSize:\t{}", 0).into()); + let sched_info = pcb.sched_info(); + let state = sched_info.inner_lock_read_irqsave().state(); + let state_str = Self::state_to_string(&pcb, state); + + let tgid: usize = pcb + .task_tgid_vnr() + .unwrap_or(crate::process::RawPid::new(0)) + .into(); + + let pid = pcb.task_pid_vnr().data(); + + let ppid = pcb.parent_pcb().map(|p| p.task_pid_vnr().data()).unwrap_or(0); + + let threads = Self::thread_count(&pcb); + + let fd_size = if matches!(state, ProcessState::Exited(_)) { + 0usize } else { - pdata.append( - &mut format!("\nFDSize:\t{}", pcb.fd_table().read().fd_open_count()).into(), - ); - } + pcb.fd_table().read().fd_open_count() + }; - // Tty - let name = if let Some(tty) = pcb.sig_info_irqsave().tty() { + let tty_name = if let Some(tty) = pcb.sig_info_irqsave().tty() { tty.core().name().clone() } else { "none".to_string() }; - pdata.append(&mut format!("\nTty:\t{}", name).as_bytes().to_owned()); - - // 进程在 CPU 上的运行时间 - pdata.append(&mut format!("\nTime:\t{}", time).as_bytes().to_owned()); - // 进程开始运行的时间 - pdata.append(&mut format!("\nStime:\t{}", start_time).as_bytes().to_owned()); - // Kthread - pdata.append(&mut format!("\nKthread:\t{}", pcb.is_kthread() as usize).into()); - pdata.append(&mut format!("\ncpu_id:\t{}", cpu_id).as_bytes().to_owned()); - pdata.append(&mut format!("\npriority:\t{:?}", priority).as_bytes().to_owned()); - pdata.append( - &mut format!("\npreempt:\t{}", pcb.preempt_count()) - .as_bytes() - .to_owned(), - ); - - pdata.append(&mut format!("\nvrtime:\t{}", vrtime).as_bytes().to_owned()); + + let cpu_id = sched_info + .on_cpu() + .map(|cpu| cpu.data() as i32) + .unwrap_or(-1); + + let priority = sched_info.policy(); + let vrtime = sched_info.sched_entity.vruntime; + let exec_runtime = sched_info.sched_entity.sum_exec_runtime; + let start_time = sched_info.sched_entity.exec_start; + + let mut vm_peak_kb = 0u64; + let mut vm_size_kb = 0u64; + let mut vm_data_kb = 0u64; + let mut vm_exe_kb = 0u64; + let vm_rss_kb = 0u64; if let Some(user_vm) = pcb.basic().user_vm() { - let address_space_guard = user_vm.read(); - // todo: 当前进程运行过程中占用内存的峰值 - let hiwater_vm: u64 = 0; - // 进程代码段的大小 - let text = (address_space_guard.end_code - address_space_guard.start_code) / 1024; - // 进程数据段的大小 - let data = (address_space_guard.end_data - address_space_guard.start_data) / 1024; - drop(address_space_guard); - pdata.append( - &mut format!("\nVmPeak:\t{} kB", hiwater_vm) - .as_bytes() - .to_owned(), - ); - pdata.append(&mut format!("\nVmData:\t{} kB", data).as_bytes().to_owned()); - pdata.append(&mut format!("\nVmExe:\t{} kB", text).as_bytes().to_owned()); - } + let as_guard = user_vm.read(); - pdata.append( - &mut format!("\nflags: {:?}\n", pcb.flags().clone()) - .as_bytes() - .to_owned(), - ); + vm_size_kb = (as_guard.vma_usage_bytes() / 1024) as u64; + vm_peak_kb = vm_size_kb; - // 去除多余的 \0 并在结尾添加 \0 - trim_string(&mut pdata); + vm_exe_kb = ((as_guard.end_code.data().saturating_sub(as_guard.start_code.data())) + / 1024) as u64; + let brk_bytes = as_guard.brk.data().saturating_sub(as_guard.brk_start.data()); + let data_bytes = + as_guard.end_data.data().saturating_sub(as_guard.start_data.data()); + vm_data_kb = (core::cmp::max(brk_bytes, data_bytes) / 1024) as u64; + } + + let mut s = String::new(); + + s.push_str("DragonOS Process Status\n"); + s.push_str("=======================\n"); + + // 基础身份信息 + Self::push_line(&mut s, "Name", pcb.basic().name()); + Self::push_line(&mut s, "State", state_str); + Self::push_line(&mut s, "Pid", pid); + Self::push_line(&mut s, "Tgid", tgid); + Self::push_line(&mut s, "PPid", ppid); + Self::push_line(&mut s, "Threads", threads); + Self::push_line(&mut s, "FDSize", fd_size); + s.push('\n'); + + // 内存相关 + Self::push_line(&mut s, "VmSize", format!("{vm_size_kb} kB")); + Self::push_line(&mut s, "VmPeak", format!("{vm_peak_kb} kB")); + Self::push_line(&mut s, "VmData", format!("{vm_data_kb} kB")); + Self::push_line(&mut s, "VmExe", format!("{vm_exe_kb} kB")); + Self::push_line(&mut s, "VmRSS", format!("{vm_rss_kb} kB")); + s.push('\n'); + + // 调度 / 运行态扩展 + Self::push_line(&mut s, "Tty", tty_name); + Self::push_line(&mut s, "Kthread", pcb.is_kthread() as usize); + Self::push_line(&mut s, "CpuId", cpu_id); + Self::push_line(&mut s, "Priority", format!("{priority:?}")); + Self::push_line(&mut s, "Preempt", pcb.preempt_count()); + Self::push_line(&mut s, "Vruntime", vrtime); + Self::push_line(&mut s, "ExecRuntime", exec_runtime); + Self::push_line(&mut s, "StartTime", start_time); + Self::push_line(&mut s, "Flags", format!("{:?}", pcb.flags().clone())); + + let mut pdata = s.into_bytes(); + trim_string(&mut pdata); Ok(pdata) } } @@ -172,8 +191,6 @@ impl FileOps for StatusFileOps { _data: MutexGuard, ) -> Result { let content = self.generate_status_content()?; - // log::info!("Generated /proc/[pid]/status content"); - proc_read(offset, len, buf, &content) } } diff --git a/kernel/src/filesystem/procfs/root.rs b/kernel/src/filesystem/procfs/root.rs index 95ee404bd4..326fb38f9d 100644 --- a/kernel/src/filesystem/procfs/root.rs +++ b/kernel/src/filesystem/procfs/root.rs @@ -8,6 +8,7 @@ use crate::{ cmdline::CmdlineFileOps, cpuinfo::CpuInfoFileOps, kmsg_file::KmsgFileOps, + uptime::UptimeFileOps, loadavg::LoadavgFileOps, meminfo::MeminfoFileOps, mounts::MountsFileOps, @@ -63,6 +64,7 @@ impl RootDirOps { ("cmdline", CmdlineFileOps::new_inode), ("cpuinfo", CpuInfoFileOps::new_inode), ("kmsg", KmsgFileOps::new_inode), + ("uptime", UptimeFileOps::new_inode), ("loadavg", LoadavgFileOps::new_inode), ("meminfo", MeminfoFileOps::new_inode), ("mounts", MountsFileOps::new_inode), @@ -85,23 +87,21 @@ impl DirOps for RootDirOps { ) -> Result, SystemError> { // 首先检查是否是 PID 目录 if let Ok(pid) = name.parse::() { - // 检查进程是否存在 - if ProcessManager::find(pid).is_some() { - let mut cached_children = dir.cached_children().write(); - - // 检查缓存中是否已存在 - if let Some(child) = cached_children.get(name) { - return Ok(child.clone()); - } - - // 创建新的 PID 目录(只传递 PID,不传递进程引用) - let inode = PidDirOps::new_inode(pid, dir.self_ref_weak().clone()); - cached_children.insert(name.to_string(), inode.clone()); - return Ok(inode); - } else { - return Err(SystemError::ENOENT); - } - } + let mut cached_children = dir.cached_children().write(); + + if ProcessManager::find(pid).is_none() { + cached_children.remove(name); + return Err(SystemError::ENOENT); + } + + if let Some(child) = cached_children.get(name) { + return Ok(child.clone()); + } + + let inode = PidDirOps::new_inode(pid, dir.self_ref_weak().clone()); + cached_children.insert(name.to_string(), inode.clone()); + return Ok(inode); +} // 查找静态条目 let mut cached_children = dir.cached_children().write(); @@ -132,17 +132,26 @@ impl DirOps for RootDirOps { // 获取缓存写锁并填充 let mut cached_children = dir.cached_children().write(); - // 填充进程目录(只传递 PID) - for pid in pid_list { - cached_children - .entry(pid.to_string()) - .or_insert_with(|| PidDirOps::new_inode(pid, dir.self_ref_weak().clone())); - } - - // 填充静态条目 - populate_children_from_table(&mut cached_children, Self::STATIC_ENTRIES, |f| { - (f)(dir.self_ref_weak().clone()) - }); + // 先删除已经失效的 PID 目录缓存 + cached_children.retain(|name, _| { + if let Ok(pid) = name.parse::() { + pid_list.contains(&pid) + } else { + true + } + }); + + // 再填充当前仍存在的 PID 目录 + for pid in pid_list.iter().copied() { + cached_children + .entry(pid.to_string()) + .or_insert_with(|| PidDirOps::new_inode(pid, dir.self_ref_weak().clone())); + } + + // 填充静态条目 + populate_children_from_table(&mut cached_children, Self::STATIC_ENTRIES, |f| { + (f)(dir.self_ref_weak().clone()) + }); // 写锁在这里自动释放 } } diff --git a/kernel/src/filesystem/procfs/stat.rs b/kernel/src/filesystem/procfs/stat.rs index 6046a24a95..78d9a4749f 100644 --- a/kernel/src/filesystem/procfs/stat.rs +++ b/kernel/src/filesystem/procfs/stat.rs @@ -1,5 +1,3 @@ -//! /proc/stat - 系统统计信息 - use crate::{ filesystem::{ procfs::{ @@ -12,6 +10,7 @@ use crate::{ process::{pid::PidType, ProcessManager, ProcessState}, sched::cputime::{kcpustat_cpu, ns_to_clock_t, CpuUsageStat, NR_CPU_STATS}, smp::cpu::{smp_cpu_manager, ProcessorId}, + time::{timekeeping::getnstimeofday, uptime_secs}, }; use alloc::{borrow::ToOwned, format, sync::Arc, sync::Weak, vec::Vec}; use system_error::SystemError; @@ -45,7 +44,7 @@ impl StatFileOps { } } - // 输出总 CPU 行(8 个字段:user nice system idle iowait irq softirq steal) + // 输出总 CPU 行 data.append( &mut format!( "cpu {} {} {} {} {} {} {} {}\n", @@ -84,9 +83,15 @@ impl StatFileOps { ); } + // 暂未接入精确的中断/上下文切换/softirq 统计,先保留标准字段 data.append(&mut b"intr 0\n".to_vec()); data.append(&mut b"ctxt 0\n".to_vec()); - data.append(&mut b"btime 0\n".to_vec()); + + // btime: 系统启动时刻(epoch 秒) + let now = getnstimeofday(); + let up = uptime_secs() as i64; + let btime = now.tv_sec.saturating_sub(up); + data.append(&mut format!("btime {}\n", btime).as_bytes().to_owned()); let pidns = ProcessManager::current_pcb().active_pid_ns(); let processes = pidns.processes_created(); @@ -94,12 +99,14 @@ impl StatFileOps { let mut procs_running = 0u64; let mut procs_blocked = 0u64; + for pid in pids { if let Some(pcb) = pid.pid_task(PidType::PID) { let state = pcb.sched_info().inner_lock_read_irqsave().state(); if state.is_runnable() { procs_running += 1; } else if matches!(state, ProcessState::Blocked(false)) { + // 按 Linux 语义,procs_blocked 更接近不可中断阻塞 procs_blocked += 1; } } @@ -135,4 +142,4 @@ impl FileOps for StatFileOps { let content = Self::generate_stat_content(); proc_read(offset, len, buf, &content) } -} +} \ No newline at end of file diff --git a/kernel/src/filesystem/procfs/uptime.rs b/kernel/src/filesystem/procfs/uptime.rs new file mode 100644 index 0000000000..f7cc5cfc6e --- /dev/null +++ b/kernel/src/filesystem/procfs/uptime.rs @@ -0,0 +1,62 @@ +use crate::libs::mutex::MutexGuard; +use crate::{ + filesystem::{ + procfs::{ + template::{Builder, FileOps, ProcFileBuilder}, + utils::{proc_read, trim_string}, + }, + vfs::{FilePrivateData, IndexNode, InodeMode}, + }, + sched::cputime::{kcpustat_cpu, CpuUsageStat}, + smp::cpu::{smp_cpu_manager, ProcessorId}, + time::uptime_secs, +}; +use alloc::{format, sync::Arc, sync::Weak, vec::Vec}; +use system_error::SystemError; + +/// /proc/uptime 文件的 FileOps 实现 +#[derive(Debug)] +pub struct UptimeFileOps; + +impl UptimeFileOps { + pub fn new_inode(parent: Weak) -> Arc { + ProcFileBuilder::new(Self, InodeMode::S_IRUGO) + .parent(parent) + .build() + .unwrap() + } + + fn generate_uptime_content() -> Vec { + let up_secs = uptime_secs(); + + let cpu_count = smp_cpu_manager().present_cpus_count() as usize; + let cpu_count = if cpu_count == 0 { 1 } else { cpu_count }; + + let mut idle_ns_total = 0u64; + for cpu_id in 0..cpu_count { + let stat = kcpustat_cpu(ProcessorId::new(cpu_id as u32)); + let snapshot = stat.snapshot(); + idle_ns_total = idle_ns_total.saturating_add(snapshot[CpuUsageStat::Idle as usize]); + } + + let idle_secs = idle_ns_total / 1_000_000_000; + let idle_hundredths = (idle_ns_total % 1_000_000_000) / 10_000_000; + + let mut data = format!("{up_secs}.00 {idle_secs}.{idle_hundredths:02}\n").into_bytes(); + trim_string(&mut data); + data + } +} + +impl FileOps for UptimeFileOps { + fn read_at( + &self, + offset: usize, + len: usize, + buf: &mut [u8], + _data: MutexGuard, + ) -> Result { + let content = Self::generate_uptime_content(); + proc_read(offset, len, buf, &content) + } +} \ No newline at end of file