use std::io;
#[cfg(all(unix, not(any(target_os = "linux", target_os = "android"))))]
use libc::{getrlimit, rlimit as Rlimit, setrlimit};
#[cfg(any(target_os = "linux", target_os = "android"))]
use libc::{getrlimit64 as getrlimit, rlimit64 as Rlimit, setrlimit64 as setrlimit};
#[cfg(unix)]
pub(super) fn increase_nofile_limit(requested: u64) -> io::Result<u64> {
increase_nofile_limit_with(requested, kernel_open_file_limit)
}
#[cfg(unix)]
#[allow(clippy::unnecessary_cast)]
fn increase_nofile_limit_with(
requested: u64,
kernel_limit: impl FnOnce() -> io::Result<u64>,
) -> io::Result<u64> {
let mut limits = open_file_limits()?;
let soft = limits.rlim_cur as u64;
let hard = limits.rlim_max as u64;
if soft >= hard {
return Ok(hard);
}
if soft >= requested {
return Ok(soft);
}
let requested = requested.min(hard).min(kernel_limit()?);
if requested <= soft {
return Ok(soft);
}
limits.rlim_cur = requested as _;
set_open_file_limits(&limits)?;
Ok(requested)
}
#[cfg(not(unix))]
pub(super) fn increase_nofile_limit(requested: u64) -> io::Result<u64> {
Ok(requested)
}
#[allow(clippy::unnecessary_cast)]
pub(super) fn current_nofile_limit() -> io::Result<u64> {
#[cfg(unix)]
{
Ok(open_file_limits()?.rlim_cur as u64)
}
#[cfg(not(unix))]
{
Err(io::Error::new(
io::ErrorKind::Unsupported,
"Unix open-file limits are unavailable on this platform",
))
}
}
#[cfg(all(
unix,
not(any(
target_vendor = "apple",
target_os = "freebsd",
target_os = "dragonfly"
))
))]
fn kernel_open_file_limit() -> io::Result<u64> {
Ok(u64::MAX)
}
#[cfg(unix)]
#[allow(unsafe_code)]
fn open_file_limits() -> io::Result<Rlimit> {
let mut limits = Rlimit {
rlim_cur: 0,
rlim_max: 0,
};
if unsafe { getrlimit(libc::RLIMIT_NOFILE, &mut limits) } != 0 {
return Err(io::Error::last_os_error());
}
Ok(limits)
}
#[cfg(unix)]
#[allow(unsafe_code)]
fn set_open_file_limits(limits: &Rlimit) -> io::Result<()> {
if unsafe { setrlimit(libc::RLIMIT_NOFILE, limits) } != 0 {
return Err(io::Error::last_os_error());
}
Ok(())
}
#[cfg(any(
target_vendor = "apple",
target_os = "freebsd",
target_os = "dragonfly"
))]
#[allow(unsafe_code)]
fn kernel_open_file_limit() -> io::Result<u64> {
let mut mib = [libc::CTL_KERN, libc::KERN_MAXFILESPERPROC];
let mib_length = mib.len() as libc::c_uint;
let mut limit: libc::c_int = 0;
let mut length = std::mem::size_of_val(&limit);
if unsafe {
libc::sysctl(
mib.as_mut_ptr(),
mib_length,
std::ptr::from_mut(&mut limit).cast(),
&mut length,
std::ptr::null_mut(),
0,
)
} != 0
{
return Err(io::Error::last_os_error());
}
if length != std::mem::size_of_val(&limit) || limit < 0 {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"kern.maxfilesperproc did not return a non-negative integer",
));
}
Ok(limit as u64)
}
#[cfg(test)]
mod tests;