liboj_cgroups/subsystem/
mod.rs1pub mod cpu;
2pub mod cpuacct;
3pub mod freezer;
4pub mod memory;
5pub mod pids;
6pub mod prelude;
7
8use std::fs;
9use std::io;
10use std::os::unix::ffi::OsStrExt;
11use std::path::{Path, PathBuf};
12
13use nix::unistd::Pid;
14
15use crate::{
16 attr_file::{AttrFile, ReadAttr, WriteAttr},
17 hierarchy::HierarchyNode,
18};
19
20pub trait Controller {
21 fn procs(&self) -> Box<dyn '_ + AttrFile<Vec<Pid>, Pid>>;
26 fn tasks(&self) -> Box<dyn '_ + AttrFile<Vec<Pid>, Pid>>;
29 fn notify_on_release(&self) -> Box<dyn '_ + AttrFile<bool>>;
31 fn release_agent(&self) -> Box<dyn '_ + AttrFile<PathBuf, Path>>;
33}
34
35impl Controller for HierarchyNode {
37 fn procs(&self) -> Box<dyn '_ + AttrFile<Vec<Pid>, Pid>> {
38 let file = self.as_path().join("cgroup.procs");
39 Box::new(PidFile(file))
40 }
41
42 fn tasks(&self) -> Box<dyn '_ + AttrFile<Vec<Pid>, Pid>> {
43 let file = self.as_path().join("tasks");
44 Box::new(PidFile(file))
45 }
46
47 fn notify_on_release(&self) -> Box<dyn '_ + AttrFile<bool, bool>> {
48 let file = self.as_path().join("notify_on_release");
49 Box::new(NotifyOnReleaseFile(file))
50 }
51
52 fn release_agent(&self) -> Box<dyn '_ + AttrFile<PathBuf, Path>> {
53 let file = self.as_path().join("release_agent");
54 Box::new(ReleaseAgentFile(file))
55 }
56}
57
58struct PidFile<P: AsRef<Path>>(P);
59
60impl<P: AsRef<Path>> ReadAttr<Vec<Pid>> for PidFile<P> {
61 fn read(&self) -> io::Result<Vec<Pid>> {
62 let file = self.0.as_ref();
63 let s = fs::read_to_string(&file)?;
64 let mut pids: Vec<Pid> = Vec::new();
65 for pid in s.split_whitespace() {
66 match pid.trim().parse() {
67 Ok(pid) => pids.push(Pid::from_raw(pid)),
68 Err(_) => {
69 return Err(io::Error::new(
70 io::ErrorKind::InvalidData,
71 format!("failed to get pid from {}", file.display()),
72 ));
73 }
74 }
75 }
76 Ok(pids)
77 }
78}
79
80impl<P: AsRef<Path>> WriteAttr<Pid> for PidFile<P> {
81 fn write(&self, pid: &Pid) -> io::Result<()> {
82 fs::write(&self.0, pid.to_string())
83 }
84}
85
86struct NotifyOnReleaseFile<P: AsRef<Path>>(P);
87
88impl<P: AsRef<Path>> ReadAttr<bool> for NotifyOnReleaseFile<P> {
89 fn read(&self) -> io::Result<bool> {
90 let file = self.0.as_ref();
91 let s = fs::read_to_string(&file)?;
92 match s.trim().parse() {
93 Ok(0u8) => Ok(false),
94 Ok(1u8) => Ok(true),
95 _ => Err(io::Error::new(
96 io::ErrorKind::InvalidData,
97 format!("failed to get flag from {}", file.display()),
98 )),
99 }
100 }
101}
102
103impl<'a, P: AsRef<Path>> WriteAttr<bool> for NotifyOnReleaseFile<P> {
104 fn write(&self, b: &bool) -> io::Result<()> {
105 fs::write(&self.0, if *b { b"1" } else { b"0" })
106 }
107}
108
109struct ReleaseAgentFile<P: AsRef<Path>>(P);
110
111impl<P: AsRef<Path>> ReadAttr<PathBuf> for ReleaseAgentFile<P> {
112 fn read(&self) -> io::Result<PathBuf> {
113 let file = self.0.as_ref();
114 let s = fs::read_to_string(&file)?;
115 Ok(PathBuf::from(s))
116 }
117}
118
119impl<P: AsRef<Path>> WriteAttr<Path> for ReleaseAgentFile<P> {
120 fn write(&self, p: &Path) -> io::Result<()> {
121 fs::write(&self.0, &p.as_os_str().as_bytes())
122 }
123}
124
125#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
126pub enum Subsystem {
127 Cpu,
128 Cpuacct,
129 Freezer,
130 Memory,
131 Pids,
132}
133
134impl Subsystem {
135 pub fn all() -> impl Iterator<Item = Subsystem> {
136 use Subsystem::*;
137 vec![Cpu, Cpuacct, Freezer, Memory, Pids].into_iter()
138 }
139
140 pub fn name(self) -> &'static str {
141 use Subsystem::*;
142 match self {
143 Cpu => "cpu",
144 Cpuacct => "cpuacct",
145 Freezer => "freezer",
146 Memory => "memory",
147 Pids => "pids",
148 }
149 }
150}