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; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -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<ProcFS>) { | ||||
|         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); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
							
								
								
									
										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_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, | ||||
|  | ||||
| @ -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<RwLock<ProcessRef>>, | ||||
|     pgrp: RwLock<Option<ProcessGrpRef>>, | ||||
| @ -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() | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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)] | ||||
|  | ||||
| @ -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<Duration> { | ||||
|  | ||||
| @ -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), | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user