use std::fs;
use std::io;
use std::path::Path;
use std::time::Duration;
use super::Controller;
use crate::{
attr_file::{AttrFile, ReadAttr, StatMap, WriteAttr},
hierarchy::HierarchyNode,
};
pub trait CpuController: Controller {
fn shares(&self) -> Box<dyn '_ + AttrFile<usize>>;
fn stat(&self) -> Box<dyn '_ + ReadAttr<Stat>>;
fn cfs_period_us(&self) -> Box<dyn '_ + AttrFile<Duration>>;
fn cfs_quota_us(&self) -> Box<dyn '_ + AttrFile<Duration>>;
}
impl CpuController for HierarchyNode {
fn shares(&self) -> Box<dyn '_ + AttrFile<usize>> {
unimplemented!()
}
fn stat(&self) -> Box<dyn '_ + ReadAttr<Stat>> {
let file = StatFile(self.as_path().join("cpu.cfs_period_us"));
Box::new(file)
}
fn cfs_period_us(&self) -> Box<dyn '_ + AttrFile<Duration>> {
let file = CpuTimeFile(self.as_path().join("cpu.cfs_period_us"));
Box::new(file)
}
fn cfs_quota_us(&self) -> Box<dyn '_ + AttrFile<Duration>> {
let file = CpuTimeFile(self.as_path().join("cpu.cfs_quota_us"));
Box::new(file)
}
}
struct CpuTimeFile<P: AsRef<Path>>(P);
impl<P: AsRef<Path>> ReadAttr<Duration> for CpuTimeFile<P> {
fn read(&self) -> io::Result<Duration> {
match fs::read_to_string(&self.0)?.trim().parse() {
Ok(us) => Ok(Duration::from_micros(us)),
Err(_) => Err(io::Error::new(
io::ErrorKind::InvalidData,
format!("failed to parse time from {}", self.0.as_ref().display()),
)),
}
}
}
impl<P: AsRef<Path>> WriteAttr<Duration> for CpuTimeFile<P> {
fn write(&self, attr: &Duration) -> io::Result<()> {
fs::write(&self.0, attr.as_micros().to_string())
}
}
struct StatFile<P: AsRef<Path>>(P);
impl<P: AsRef<Path>> ReadAttr<Stat> for StatFile<P> {
fn read(&self) -> io::Result<Stat> {
let s = fs::read_to_string(&self.0)?;
let stat_map = StatMap::from(s.as_str());
let res = stat_attr!(stat_map, Stat, [nr_periods, nr_throttled, throttled_time]);
Ok(res)
}
}
pub struct Stat {
pub nr_periods: u64,
pub nr_throttled: u64,
pub throttled_time: u64,
}