Add partial support for '/proc/stat' and '/proc/[pid]/stat'
This commit is contained in:
parent
178bd023e3
commit
64c75e6d40
@ -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;
|
||||||
|
48
src/libos/src/fs/procfs/stat.rs
Normal file
48
src/libos/src/fs/procfs/stat.rs
Normal file
@ -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),
|
||||||
|
Loading…
Reference in New Issue
Block a user