pub fn available_memory_bytes() -> usize {
if let Some(v) = cgroup_v2_memory_max() {
return v;
}
let pages = unsafe { libc::sysconf(libc::_SC_PHYS_PAGES) };
let page_size = unsafe { libc::sysconf(libc::_SC_PAGE_SIZE) };
if pages > 0 && page_size > 0 {
(pages as usize).saturating_mul(page_size as usize)
} else {
0
}
}
fn cgroup_v2_memory_max() -> Option<usize> {
let cgroup = std::fs::read_to_string("/proc/self/cgroup").ok()?;
tightest_memory_max(&cgroup, std::path::Path::new("/sys/fs/cgroup"))
}
fn tightest_memory_max(proc_cgroup: &str, root: &std::path::Path) -> Option<usize> {
let rel = proc_cgroup.lines().find_map(|l| l.strip_prefix("0::"))?.trim();
root.join(rel.trim_start_matches('/'))
.ancestors()
.take_while(|d| d.starts_with(root))
.filter_map(|d| std::fs::read_to_string(d.join("memory.max")).ok())
.filter_map(|s| s.trim().parse::<usize>().ok())
.filter(|&v| v > 0)
.min()
}
#[cfg(test)]
#[path = "tests/host.rs"]
mod tests;