Move to the new std::io APIs for parsing proc files

The implementation is certainly not cleaner to look at.  For whatever
reason, the noticeable delay that was present on startup previously
is now gone, so some performance issue must have been resolved with
this change as well.
This commit is contained in:
Paul Osborne 2015-03-06 00:25:38 -06:00
parent 8d9bf2cefb
commit 99b4bdd596

View file

@ -27,14 +27,15 @@
// of different items, notably the process name and its parent process id (ppid). // of different items, notably the process name and its parent process id (ppid).
// And with that information, we can build the process tree. // And with that information, we can build the process tree.
#![feature(old_io)]
#![feature(old_path)]
#![feature(std_misc)] // hash_map::Entry #![feature(std_misc)] // hash_map::Entry
#![feature(path)]
#![feature(fs)]
#![feature(io)]
use std::old_io::fs::PathExtensions; use std::path::Path;
use std::old_io::fs; use std::fs;
use std::old_io::File; use std::io::prelude::*;
use std::old_io::BufferedReader; use std::fs::File;
use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::collections::HashMap; use std::collections::HashMap;
@ -71,22 +72,29 @@ fn get_process_record(status_path: &Path) -> Option<ProcessRecord> {
let mut ppid : Option<i32> = None; let mut ppid : Option<i32> = None;
let mut name : Option<String> = None; let mut name : Option<String> = None;
let mut status_file = BufferedReader::new(File::open(status_path)); let mut reader = std::io::BufReader::new(File::open(status_path).unwrap());
for line in status_file.lines() { loop {
let unwrapped = line.unwrap(); // need a new lifeline let mut linebuf = String::new();
let parts : Vec<&str> = unwrapped[..].splitn(2, ':').collect(); match reader.read_line(&mut linebuf) {
if parts.len() == 2 { Ok(_) => {
let key = parts[0].trim(); if linebuf.is_empty() {
let value = parts[1].trim(); break;
match key { }
"Name" => name = Some(value.to_string()), let parts : Vec<&str> = linebuf[..].splitn(2, ':').collect();
"Pid" => pid = value.parse().ok(), if parts.len() == 2 {
"PPid" => ppid = value.parse().ok(), let key = parts[0].trim();
_ => (), let value = parts[1].trim();
} match key {
"Name" => name = Some(value.to_string()),
"Pid" => pid = value.parse().ok(),
"PPid" => ppid = value.parse().ok(),
_ => (),
}
}
},
Err(_) => break,
} }
} }
return if pid.is_some() && ppid.is_some() && name.is_some() { return if pid.is_some() && ppid.is_some() && name.is_some() {
Some(ProcessRecord { name: name.unwrap(), pid: pid.unwrap(), ppid: ppid.unwrap() }) Some(ProcessRecord { name: name.unwrap(), pid: pid.unwrap(), ppid: ppid.unwrap() })
} else { } else {
@ -100,10 +108,11 @@ fn get_process_records() -> Vec<ProcessRecord> {
let proc_directory = Path::new("/proc"); let proc_directory = Path::new("/proc");
// find potential process directories under /proc // find potential process directories under /proc
let proc_directory_contents = fs::readdir(&proc_directory).unwrap(); let proc_directory_contents = fs::read_dir(&proc_directory).unwrap();
proc_directory_contents.iter().filter_map(|entry| { proc_directory_contents.filter_map(|entry| {
if entry.is_dir() { let entry_path = entry.unwrap().path();
let status_path = entry.join("status"); if entry_path.is_dir() {
let status_path = entry_path.join("status");
if status_path.exists() { if status_path.exists() {
return get_process_record(&status_path) return get_process_record(&status_path)
} }