liboj_cgroups/subsystem/
mod.rs

1pub 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    /// List of thread group IDs in the cgroup. This list is not guaranteed to be sorted
22    /// or free of duplicate TGIDs, and userspace should sort/uniquify the list if this
23    /// property is required. Writing a thread group ID into this file moves all threads
24    /// in that group into this cgroup.
25    fn procs(&self) -> Box<dyn '_ + AttrFile<Vec<Pid>, Pid>>;
26    /// List of tasks (by PID) attached to that cgroup. This list is not guaranteed to be
27    /// sorted. Writing a thread ID into this file moves the thread into this cgroup.
28    fn tasks(&self) -> Box<dyn '_ + AttrFile<Vec<Pid>, Pid>>;
29    /// Flag if run the release agent on exit?
30    fn notify_on_release(&self) -> Box<dyn '_ + AttrFile<bool>>;
31    /// The path to use for release notifications (exists in the top cgroup only)
32    fn release_agent(&self) -> Box<dyn '_ + AttrFile<PathBuf, Path>>;
33}
34
35/// Hierarchy in the cgroup.
36impl 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}