#[macro_use]
extern crate cfg_if;
cfg_if! {
if #[cfg(all(target_os = "linux", target_env = "gnu"))]{
use libc::__rlimit_resource_t as __resource_t;
}else{
use libc::c_int as __resource_t;
}
}
use libc::rlim_t as __rlim_t;
use libc::rlimit as __rlimit;
use libc::getrlimit as __getrlimit;
use libc::setrlimit as __setrlimit;
#[cfg(target_os = "linux")]
use libc::prlimit as __prlimit;
#[allow(non_camel_case_types)]
pub type rlim = __rlim_t;
pub const RLIM_INFINITY: rlim = libc::RLIM_INFINITY;
pub type RawResource = __resource_t;
#[repr(i32)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Resource {
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "ios"))]
AS = libc::RLIMIT_AS as _,
CORE = libc::RLIMIT_CORE as _,
CPU = libc::RLIMIT_CPU as _,
DATA = libc::RLIMIT_DATA as _,
FSIZE = libc::RLIMIT_FSIZE as _,
#[cfg(target_os = "linux")]
LOCKS = libc::RLIMIT_LOCKS as _,
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "ios"))]
MEMLOCK = libc::RLIMIT_MEMLOCK as _,
#[cfg(target_os = "linux")]
MSGQUEUE = libc::RLIMIT_MSGQUEUE as _,
#[cfg(target_os = "linux")]
NICE = libc::RLIMIT_NICE as _,
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "ios"))]
NOFILE = libc::RLIMIT_NOFILE as _,
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "ios"))]
NPROC = libc::RLIMIT_NPROC as _,
#[cfg(target_os = "linux")]
RSS = libc::RLIMIT_RSS as _,
#[cfg(target_os = "linux")]
RTPRIO = libc::RLIMIT_RTPRIO as _,
#[cfg(all(target_os = "linux", target_env = "gnu"))]
RTTIME = libc::RLIMIT_RTTIME as _,
#[cfg(target_os = "linux")]
SIGPENDING = libc::RLIMIT_SIGPENDING as _,
STACK = libc::RLIMIT_STACK as _,
}
impl Resource {
#[inline(always)]
pub fn as_raw_resource(&self) -> RawResource {
*self as _
}
#[inline(always)]
pub fn set(&self, soft: rlim, hard: rlim) -> std::io::Result<()> {
setrlimit(*self, soft, hard)
}
#[inline(always)]
pub fn get(&self) -> std::io::Result<(rlim, rlim)> {
getrlimit(*self)
}
}
pub fn setrlimit(resource: Resource, soft: rlim, hard: rlim) -> std::io::Result<()> {
let resource = resource.as_raw_resource();
let limit = __rlimit {
rlim_cur: soft,
rlim_max: hard,
};
let ret = unsafe { __setrlimit(resource as _, &limit) };
if ret == 0 {
Ok(())
} else {
Err(std::io::Error::last_os_error())
}
}
pub fn getrlimit(resource: Resource) -> std::io::Result<(rlim, rlim)> {
let resource = resource.as_raw_resource();
let mut limit = std::mem::MaybeUninit::<__rlimit>::uninit();
let ret = unsafe { __getrlimit(resource as _, limit.as_mut_ptr()) };
if ret == 0 {
let limit = unsafe { limit.assume_init() };
Ok((limit.rlim_cur, limit.rlim_max))
} else {
Err(std::io::Error::last_os_error())
}
}
#[cfg(target_os = "linux")]
pub fn prlimit(
pid: libc::pid_t,
resource: Resource,
new_limit: Option<(rlim, rlim)>,
) -> std::io::Result<()> {
let resource = resource.as_raw_resource();
let new_rlimit = new_limit.map(|(soft, hard)| __rlimit {
rlim_cur: soft,
rlim_max: hard,
});
let new_rlimit_ptr = new_rlimit
.as_ref()
.map(|r| r as *const _)
.unwrap_or(std::ptr::null());
let ret = unsafe { __prlimit(pid, resource, new_rlimit_ptr, std::ptr::null_mut()) };
if ret == 0 {
Ok(())
} else {
Err(std::io::Error::last_os_error())
}
}
#[cfg(target_os = "linux")]
pub fn prlimit_with_old(
pid: libc::pid_t,
resource: Resource,
new_limit: Option<(rlim, rlim)>,
) -> std::io::Result<(rlim, rlim)> {
let resource = resource.as_raw_resource();
let new_rlimit = new_limit.map(|(soft, hard)| __rlimit {
rlim_cur: soft,
rlim_max: hard,
});
let new_rlimit_ptr = new_rlimit
.as_ref()
.map(|r| r as *const _)
.unwrap_or(std::ptr::null());
let mut old_rlimit = std::mem::MaybeUninit::<__rlimit>::uninit();
let ret = unsafe { __prlimit(pid, resource, new_rlimit_ptr, old_rlimit.as_mut_ptr()) };
if ret == 0 {
let old_rlimit = unsafe { old_rlimit.assume_init() };
Ok((old_rlimit.rlim_cur, old_rlimit.rlim_max))
} else {
Err(std::io::Error::last_os_error())
}
}