Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 40 additions & 56 deletions kernel/src/filesystem/procfs/meminfo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ use crate::{
mm::page_cache_stats,
};
use alloc::{
borrow::ToOwned,
format,
string::String,
sync::{Arc, Weak},
vec::Vec,
};
Expand All @@ -36,68 +36,52 @@ impl MeminfoFileOps {
}

fn generate_meminfo_content() -> Vec<u8> {
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<u8> = 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
}
}

Expand Down
1 change: 1 addition & 0 deletions kernel/src/filesystem/procfs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ mod cpuinfo;
pub mod klog;
pub mod kmsg;
mod kmsg_file;
mod uptime;
mod loadavg;
mod meminfo;
mod mounts;
Expand Down
4 changes: 3 additions & 1 deletion kernel/src/filesystem/procfs/pid/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Self>,
Expand Down
75 changes: 47 additions & 28 deletions kernel/src/filesystem/procfs/pid/stat.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
//! /proc/[pid]/stat - 进程状态信息
//!
//! 以单行格式返回进程的状态信息,兼容 Linux procfs 格式

use core::sync::atomic::Ordering;

use crate::libs::mutex::MutexGuard;
Expand All @@ -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::{
Expand All @@ -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) => {
Expand All @@ -63,18 +66,42 @@ fn sanitize_comm_for_proc_stat(comm: &str) -> String {
.collect()
}

/// 统计线程组中的线程数量
fn thread_count(pcb: &Arc<ProcessControlBlock>) -> 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<ProcessControlBlock>,
) -> 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
Expand All @@ -83,37 +110,35 @@ 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));

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()
Expand All @@ -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()
Expand All @@ -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(),
)
}

Expand All @@ -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())
}
}
}
Loading
Loading