Add partial support for '/proc/stat' and '/proc/[pid]/stat'

This commit is contained in:
LI Qing 2021-05-27 12:48:17 +08:00 committed by volcano
parent 178bd023e3
commit 64c75e6d40
10 changed files with 98 additions and 6 deletions

@ -336,7 +336,7 @@ impl HNode {
} }
} }
trait IntoFsError { pub trait IntoFsError {
fn into_fs_error(self) -> FsError; fn into_fs_error(self) -> FsError;
} }

@ -10,12 +10,14 @@ use self::meminfo::MemInfoINode;
use self::pid::LockedPidDirINode; use self::pid::LockedPidDirINode;
use self::proc_inode::{Dir, DirProcINode, File, ProcINode, SymLink}; use self::proc_inode::{Dir, DirProcINode, File, ProcINode, SymLink};
use self::self_::SelfSymINode; use self::self_::SelfSymINode;
use self::stat::StatINode;
mod cpuinfo; mod cpuinfo;
mod meminfo; mod meminfo;
mod pid; mod pid;
mod proc_inode; mod proc_inode;
mod self_; mod self_;
mod stat;
// Same with the procfs on Linux // Same with the procfs on Linux
const PROC_SUPER_MAGIC: usize = 0x9fa0; const PROC_SUPER_MAGIC: usize = 0x9fa0;
@ -97,7 +99,6 @@ impl LockedProcRootINode {
fn init(&self, fs: &Arc<ProcFS>) { fn init(&self, fs: &Arc<ProcFS>) {
let mut file = self.0.write().unwrap(); let mut file = self.0.write().unwrap();
file.this = Arc::downgrade(&fs.root); file.this = Arc::downgrade(&fs.root);
// Currently, we only init the 'cpuinfo', 'meminfo' and 'self' entry.
// TODO: Add more entries for root. // TODO: Add more entries for root.
// All [pid] entries are lazy-initialized at the find() step. // All [pid] entries are lazy-initialized at the find() step.
let cpuinfo_inode = CpuInfoINode::new(); let cpuinfo_inode = CpuInfoINode::new();
@ -109,6 +110,9 @@ impl LockedProcRootINode {
let self_inode = SelfSymINode::new(); let self_inode = SelfSymINode::new();
file.non_volatile_entries file.non_volatile_entries
.insert(String::from("self"), self_inode); .insert(String::from("self"), self_inode);
let stat_inode = StatINode::new();
file.non_volatile_entries
.insert(String::from("stat"), stat_inode);
} }
} }

@ -36,11 +36,11 @@ impl ProcINode for ProcStatINode {
let stime = 0; let stime = 0;
let cutime = 0; let cutime = 0;
let cstime = 0; let cstime = 0;
let priority = 0; let priority = main_thread.nice().read().unwrap().to_priority_val();
let nice = 0; let nice = main_thread.nice().read().unwrap().raw_val();
let num_threads = self.0.threads().len(); let num_threads = self.0.threads().len();
let itrealvalue = 0; let itrealvalue = 0;
let starttime = 0; let starttime = self.0.start_time();
let vsize = main_thread.vm().get_process_range().size(); let vsize = main_thread.vm().get_process_range().size();
let rss = 0; let rss = 0;
let rsslim = 0; let rsslim = 0;

@ -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<dyn INode> {
Arc::new(File::new(Self))
}
}
impl ProcINode for StatINode {
fn generate_data_in_bytes(&self) -> vfs::Result<Vec<u8>> {
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);
}

@ -135,9 +135,11 @@ impl ProcessBuilder {
let sig_dispositions = RwLock::new(self.sig_dispositions.unwrap_or_default()); let sig_dispositions = RwLock::new(self.sig_dispositions.unwrap_or_default());
let sig_queues = RwLock::new(SigQueues::new()); let sig_queues = RwLock::new(SigQueues::new());
let forced_exit_status = ForcedExitStatus::new(); let forced_exit_status = ForcedExitStatus::new();
let start_time = crate::time::up_time::get().unwrap();
Arc::new(Process { Arc::new(Process {
pid, pid,
exec_path, exec_path,
start_time,
umask, umask,
parent, parent,
pgrp, pgrp,

@ -1,4 +1,5 @@
use std::fmt; use std::fmt;
use std::time::Duration;
use super::wait::WaitQueue; use super::wait::WaitQueue;
use super::{ForcedExitStatus, ProcessGrpRef, ProcessRef, TermStatus, ThreadRef}; use super::{ForcedExitStatus, ProcessGrpRef, ProcessRef, TermStatus, ThreadRef};
@ -16,6 +17,7 @@ pub struct Process {
// Immutable info // Immutable info
pid: pid_t, pid: pid_t,
exec_path: String, exec_path: String,
start_time: Duration,
// Mutable info // Mutable info
parent: Option<RwLock<ProcessRef>>, parent: Option<RwLock<ProcessRef>>,
pgrp: RwLock<Option<ProcessGrpRef>>, pgrp: RwLock<Option<ProcessGrpRef>>,
@ -124,6 +126,13 @@ impl Process {
&self.exec_path &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 /// Get the file mode creation mask
pub fn umask(&self) -> FileMode { pub fn umask(&self) -> FileMode {
self.umask.read().unwrap().clone() self.umask.read().unwrap().clone()

@ -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]. /// Convert [19,-20] to rlimit style value [1,40].
pub fn to_rlimit_val(&self) -> i32 { pub fn to_rlimit_val(&self) -> i32 {
Self::MAX_PRIO - self.value + 1 Self::MAX_PRIO - self.value + 1

@ -24,6 +24,9 @@ pub type suseconds_t = i64;
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
pub type clock_t = i64; pub type clock_t = i64;
/// Clock ticks per second
pub const SC_CLK_TCK: u64 = 100;
#[repr(C)] #[repr(C)]
#[derive(Debug, Default, Copy, Clone)] #[derive(Debug, Default, Copy, Clone)]
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]

@ -5,10 +5,18 @@ lazy_static! {
static ref BOOT_TIME_STAMP: Duration = do_clock_gettime(ClockID::CLOCK_MONOTONIC_RAW) static ref BOOT_TIME_STAMP: Duration = do_clock_gettime(ClockID::CLOCK_MONOTONIC_RAW)
.unwrap() .unwrap()
.as_duration(); .as_duration();
static ref BOOT_TIME_STAMP_SINCE_EPOCH: Duration = do_clock_gettime(ClockID::CLOCK_REALTIME)
.unwrap()
.as_duration();
} }
pub fn init() { pub fn init() {
*BOOT_TIME_STAMP; *BOOT_TIME_STAMP;
*BOOT_TIME_STAMP_SINCE_EPOCH;
}
pub fn boot_time_since_epoch() -> Duration {
*BOOT_TIME_STAMP_SINCE_EPOCH
} }
pub fn get() -> Option<Duration> { pub fn get() -> Option<Duration> {

@ -48,7 +48,6 @@ static int test_read_from_procfs(const char *proc_inode) {
return 0; return 0;
} }
// ============================================================================ // ============================================================================
// Test cases for procfs // Test cases for procfs
// ============================================================================ // ============================================================================
@ -207,6 +206,15 @@ static int test_read_from_proc_cpuinfo() {
return 0; 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 #define PROC_SUPER_MAGIC 0x9fa0
static int test_statfs() { static int test_statfs() {
const char *file_path = "/proc/cpuinfo"; 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_self_stat),
TEST_CASE(test_read_from_proc_meminfo), TEST_CASE(test_read_from_proc_meminfo),
TEST_CASE(test_read_from_proc_cpuinfo), TEST_CASE(test_read_from_proc_cpuinfo),
TEST_CASE(test_read_from_proc_stat),
TEST_CASE(test_statfs), TEST_CASE(test_statfs),
TEST_CASE(test_readdir_root), TEST_CASE(test_readdir_root),
TEST_CASE(test_readdir_self), TEST_CASE(test_readdir_self),