1use eventfd::{eventfd, EfdFlags};
7use nix::sys::eventfd;
8use std::fs::{self, File};
9use std::io::Read;
10use std::os::unix::io::{AsRawFd, FromRawFd};
11use std::path::Path;
12use std::sync::mpsc::{self, Receiver};
13use std::thread;
14
15use crate::fs::error::ErrorKind::*;
16use crate::fs::error::*;
17
18pub fn notify_on_oom_v2(key: &str, dir: &Path) -> Result<Receiver<String>> {
21 register_memory_event(key, dir, "memory.oom_control", "")
22}
23
24pub fn notify_on_oom_v1(key: &str, dir: &Path) -> Result<Receiver<String>> {
27 register_memory_event(key, dir, "memory.oom_control", "")
28}
29
30pub fn notify_memory_pressure(key: &str, dir: &Path, level: &str) -> Result<Receiver<String>> {
32 if level != "low" && level != "medium" && level != "critical" {
33 return Err(Error::from_string(format!(
34 "invalid pressure level {}",
35 level
36 )));
37 }
38
39 register_memory_event(key, dir, "memory.pressure_level", level)
40}
41
42fn register_memory_event(
43 key: &str,
44 cg_dir: &Path,
45 event_name: &str,
46 arg: &str,
47) -> Result<Receiver<String>> {
48 let path = cg_dir.join(event_name);
49 let event_file = File::open(path.clone())
50 .map_err(|e| Error::with_cause(ReadFailed(path.display().to_string()), e))?;
51
52 let eventfd = eventfd(0, EfdFlags::EFD_CLOEXEC)
53 .map_err(|e| Error::with_cause(ReadFailed("eventfd".to_string()), e))?;
54
55 let event_control_path = cg_dir.join("cgroup.event_control");
56 let data = if arg.is_empty() {
57 format!("{} {}", eventfd, event_file.as_raw_fd())
58 } else {
59 format!("{} {} {}", eventfd, event_file.as_raw_fd(), arg)
60 };
61
62 fs::write(&event_control_path, data.clone()).map_err(|e| {
64 Error::with_cause(
65 WriteFailed(event_control_path.display().to_string(), data),
66 e,
67 )
68 })?;
69
70 let mut eventfd_file = unsafe { File::from_raw_fd(eventfd) };
71
72 let (sender, receiver) = mpsc::channel();
73 let key = key.to_string();
74
75 thread::spawn(move || {
76 loop {
77 let mut buf = [0; 8];
78 if eventfd_file.read(&mut buf).is_err() {
79 return;
80 }
81
82 if !Path::new(&event_control_path).exists() {
85 return;
86 }
87 sender.send(key.clone()).unwrap();
88 }
89 });
90
91 Ok(receiver)
92}