From 64c75e6d40ec72aa458dd5d8dc2ccd4382ce9880 Mon Sep 17 00:00:00 2001 From: LI Qing Date: Thu, 27 May 2021 12:48:17 +0800 Subject: [PATCH] Add partial support for '/proc/stat' and '/proc/[pid]/stat' --- src/libos/src/fs/hostfs.rs | 2 +- src/libos/src/fs/procfs/mod.rs | 6 ++- src/libos/src/fs/procfs/pid/stat.rs | 6 +-- src/libos/src/fs/procfs/stat.rs | 48 ++++++++++++++++++++++++ src/libos/src/process/process/builder.rs | 2 + src/libos/src/process/process/mod.rs | 9 +++++ src/libos/src/sched/priority.rs | 9 +++++ src/libos/src/time/mod.rs | 3 ++ src/libos/src/time/up_time.rs | 8 ++++ test/procfs/main.c | 11 +++++- 10 files changed, 98 insertions(+), 6 deletions(-) create mode 100644 src/libos/src/fs/procfs/stat.rs diff --git a/src/libos/src/fs/hostfs.rs b/src/libos/src/fs/hostfs.rs index b3f096b5..e58623ba 100644 --- a/src/libos/src/fs/hostfs.rs +++ b/src/libos/src/fs/hostfs.rs @@ -336,7 +336,7 @@ impl HNode { } } -trait IntoFsError { +pub trait IntoFsError { fn into_fs_error(self) -> FsError; } diff --git a/src/libos/src/fs/procfs/mod.rs b/src/libos/src/fs/procfs/mod.rs index 5edfce7a..5ae407db 100644 --- a/src/libos/src/fs/procfs/mod.rs +++ b/src/libos/src/fs/procfs/mod.rs @@ -10,12 +10,14 @@ use self::meminfo::MemInfoINode; use self::pid::LockedPidDirINode; use self::proc_inode::{Dir, DirProcINode, File, ProcINode, SymLink}; use self::self_::SelfSymINode; +use self::stat::StatINode; mod cpuinfo; mod meminfo; mod pid; mod proc_inode; mod self_; +mod stat; // Same with the procfs on Linux const PROC_SUPER_MAGIC: usize = 0x9fa0; @@ -97,7 +99,6 @@ impl LockedProcRootINode { fn init(&self, fs: &Arc) { let mut file = self.0.write().unwrap(); file.this = Arc::downgrade(&fs.root); - // Currently, we only init the 'cpuinfo', 'meminfo' and 'self' entry. // TODO: Add more entries for root. // All [pid] entries are lazy-initialized at the find() step. let cpuinfo_inode = CpuInfoINode::new(); @@ -109,6 +110,9 @@ impl LockedProcRootINode { let self_inode = SelfSymINode::new(); file.non_volatile_entries .insert(String::from("self"), self_inode); + let stat_inode = StatINode::new(); + file.non_volatile_entries + .insert(String::from("stat"), stat_inode); } } diff --git a/src/libos/src/fs/procfs/pid/stat.rs b/src/libos/src/fs/procfs/pid/stat.rs index 70951d7d..6a35d668 100644 --- a/src/libos/src/fs/procfs/pid/stat.rs +++ b/src/libos/src/fs/procfs/pid/stat.rs @@ -36,11 +36,11 @@ impl ProcINode for ProcStatINode { let stime = 0; let cutime = 0; let cstime = 0; - let priority = 0; - let nice = 0; + let priority = main_thread.nice().read().unwrap().to_priority_val(); + let nice = main_thread.nice().read().unwrap().raw_val(); let num_threads = self.0.threads().len(); let itrealvalue = 0; - let starttime = 0; + let starttime = self.0.start_time(); let vsize = main_thread.vm().get_process_range().size(); let rss = 0; let rsslim = 0; diff --git a/src/libos/src/fs/procfs/stat.rs b/src/libos/src/fs/procfs/stat.rs new file mode 100644 index 00000000..38e67771 --- /dev/null +++ b/src/libos/src/fs/procfs/stat.rs @@ -0,0 +1,48 @@ +use super::*; +use crate::fs::hostfs::IntoFsError; +use std::untrusted::fs; + +/// It returns most of the information from host OS's "/proc/stat", +/// and some fields will be filled in with LibOS's information. +pub struct StatINode; + +impl StatINode { + pub fn new() -> Arc { + Arc::new(File::new(Self)) + } +} + +impl ProcINode for StatINode { + fn generate_data_in_bytes(&self) -> vfs::Result> { + let mut host_stat = fs::read_to_string("/proc/stat").map_err(|e| e.into_fs_error())?; + let boot_time = crate::time::up_time::boot_time_since_epoch() + .as_secs() + .to_string(); + fill_in_stat(&mut host_stat, "btime", &boot_time); + let procs_running = { + let mut processes = crate::process::table::get_all_processes(); + processes.retain(|p| p.status() == crate::process::ProcessStatus::Running); + processes.len().to_string() + }; + fill_in_stat(&mut host_stat, "procs_running", &procs_running); + Ok(host_stat.into_bytes()) + } +} + +fn fill_in_stat(stat: &mut String, pat: &str, val: &str) { + let start_idx = stat.find(pat).unwrap_or_else(|| { + error!("failed to find {} in host's /proc/stat", pat); + panic!() + }) + pat.len() + + 1; + let end_idx = stat + .chars() + .skip(start_idx) + .position(|c| c == '\n') + .unwrap_or_else(|| { + error!("invalid format of host's /proc/stat"); + panic!() + }) + + start_idx; + stat.replace_range(start_idx..end_idx, val); +} diff --git a/src/libos/src/process/process/builder.rs b/src/libos/src/process/process/builder.rs index 6430c0d4..d0e53b27 100644 --- a/src/libos/src/process/process/builder.rs +++ b/src/libos/src/process/process/builder.rs @@ -135,9 +135,11 @@ impl ProcessBuilder { let sig_dispositions = RwLock::new(self.sig_dispositions.unwrap_or_default()); let sig_queues = RwLock::new(SigQueues::new()); let forced_exit_status = ForcedExitStatus::new(); + let start_time = crate::time::up_time::get().unwrap(); Arc::new(Process { pid, exec_path, + start_time, umask, parent, pgrp, diff --git a/src/libos/src/process/process/mod.rs b/src/libos/src/process/process/mod.rs index 578a2291..30e93dc8 100644 --- a/src/libos/src/process/process/mod.rs +++ b/src/libos/src/process/process/mod.rs @@ -1,4 +1,5 @@ use std::fmt; +use std::time::Duration; use super::wait::WaitQueue; use super::{ForcedExitStatus, ProcessGrpRef, ProcessRef, TermStatus, ThreadRef}; @@ -16,6 +17,7 @@ pub struct Process { // Immutable info pid: pid_t, exec_path: String, + start_time: Duration, // Mutable info parent: Option>, pgrp: RwLock>, @@ -124,6 +126,13 @@ impl Process { &self.exec_path } + /// Get the time the process started after system boot + /// + /// The value is expressed in clock ticks + pub fn start_time(&self) -> u64 { + self.start_time.as_millis() as u64 * crate::time::SC_CLK_TCK / 1000 + } + /// Get the file mode creation mask pub fn umask(&self) -> FileMode { self.umask.read().unwrap().clone() diff --git a/src/libos/src/sched/priority.rs b/src/libos/src/sched/priority.rs index 4305d818..6601888f 100644 --- a/src/libos/src/sched/priority.rs +++ b/src/libos/src/sched/priority.rs @@ -46,6 +46,15 @@ impl NiceValue { } } + pub fn raw_val(&self) -> i32 { + self.value + } + + /// Convert [19,-20] to priority value [39,0]. + pub fn to_priority_val(&self) -> i32 { + self.value - Self::MIN_PRIO + } + /// Convert [19,-20] to rlimit style value [1,40]. pub fn to_rlimit_val(&self) -> i32 { Self::MAX_PRIO - self.value + 1 diff --git a/src/libos/src/time/mod.rs b/src/libos/src/time/mod.rs index ef90b3a4..d6dfac4e 100644 --- a/src/libos/src/time/mod.rs +++ b/src/libos/src/time/mod.rs @@ -24,6 +24,9 @@ pub type suseconds_t = i64; #[allow(non_camel_case_types)] pub type clock_t = i64; +/// Clock ticks per second +pub const SC_CLK_TCK: u64 = 100; + #[repr(C)] #[derive(Debug, Default, Copy, Clone)] #[allow(non_camel_case_types)] diff --git a/src/libos/src/time/up_time.rs b/src/libos/src/time/up_time.rs index a9feabba..2078c0e5 100644 --- a/src/libos/src/time/up_time.rs +++ b/src/libos/src/time/up_time.rs @@ -5,10 +5,18 @@ lazy_static! { static ref BOOT_TIME_STAMP: Duration = do_clock_gettime(ClockID::CLOCK_MONOTONIC_RAW) .unwrap() .as_duration(); + static ref BOOT_TIME_STAMP_SINCE_EPOCH: Duration = do_clock_gettime(ClockID::CLOCK_REALTIME) + .unwrap() + .as_duration(); } pub fn init() { *BOOT_TIME_STAMP; + *BOOT_TIME_STAMP_SINCE_EPOCH; +} + +pub fn boot_time_since_epoch() -> Duration { + *BOOT_TIME_STAMP_SINCE_EPOCH } pub fn get() -> Option { diff --git a/test/procfs/main.c b/test/procfs/main.c index 76ec01e8..05e75e94 100644 --- a/test/procfs/main.c +++ b/test/procfs/main.c @@ -48,7 +48,6 @@ static int test_read_from_procfs(const char *proc_inode) { return 0; } - // ============================================================================ // Test cases for procfs // ============================================================================ @@ -207,6 +206,15 @@ static int test_read_from_proc_cpuinfo() { return 0; } +static int test_read_from_proc_stat() { + const char *proc_stat = "/proc/stat"; + + if (test_read_from_procfs(proc_stat) < 0) { + THROW_ERROR("failed to read the stat"); + } + return 0; +} + #define PROC_SUPER_MAGIC 0x9fa0 static int test_statfs() { const char *file_path = "/proc/cpuinfo"; @@ -288,6 +296,7 @@ static test_case_t test_cases[] = { TEST_CASE(test_read_from_proc_self_stat), TEST_CASE(test_read_from_proc_meminfo), TEST_CASE(test_read_from_proc_cpuinfo), + TEST_CASE(test_read_from_proc_stat), TEST_CASE(test_statfs), TEST_CASE(test_readdir_root), TEST_CASE(test_readdir_self),