Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/sys/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ pub mod quota;
#[cfg(any(target_os = "linux"))]
pub mod reboot;

pub mod resource;

pub mod select;

// TODO: Add support for dragonfly, freebsd, and ios/macos.
Expand Down
69 changes: 69 additions & 0 deletions src/sys/resource.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
use std::mem;

use libc::{self, c_int};
pub use libc::{rlimit, rlim_t, RLIM_INFINITY};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand why you're reexporting rlim_t, but why reexport the others?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, limited the reexport to rlim_t


#[cfg(any(target_os = "linux",
target_os = "openbsd",
target_os = "netbsd",
target_os = "bitrig"))]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bitrig no longer exists, do go ahead and drop this. But please add fuchsia and empscripten, as they also support this API.

Additionally these targets should be alphabetized.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, removed the import.

pub use libc::{RLIM_SAVED_CUR, RLIM_SAVED_MAX};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why reexport these symbols? For that matter, why import them? It seems like nothing is using them.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, removed the import.


use {Errno, Result};

#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[repr(i32)]
pub enum Resource {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use the libc_enum! macro instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

// POSIX
RLIMIT_CORE = libc::RLIMIT_CORE,
RLIMIT_CPU = libc::RLIMIT_CPU,
RLIMIT_DATA = libc::RLIMIT_DATA,
RLIMIT_FSIZE = libc::RLIMIT_FSIZE,
RLIMIT_NOFILE = libc::RLIMIT_NOFILE,
RLIMIT_STACK = libc::RLIMIT_STACK,
RLIMIT_AS = libc::RLIMIT_AS,
// BSDs and Linux
#[cfg(all(unix, not(target_os = "solaris")))]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't use not, explicitly list targets here instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

RLIMIT_MEMLOCK = libc::RLIMIT_MEMLOCK,
#[cfg(all(unix, not(target_os = "solaris")))]
RLIMIT_NPROC = libc::RLIMIT_NPROC,
#[cfg(all(unix, not(target_os = "solaris")))]
RLIMIT_RSS = libc::RLIMIT_RSS,
// Linux-only
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Android and Linux only"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

#[cfg(any(target_os = "linux", target_os = "android"))]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These also need to be alphabetized.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

RLIMIT_LOCKS = libc::RLIMIT_LOCKS,
#[cfg(any(target_os = "linux", target_os = "android"))]
RLIMIT_MSGQUEUE = libc::RLIMIT_MSGQUEUE,
#[cfg(any(target_os = "linux", target_os = "android"))]
RLIMIT_NICE = libc::RLIMIT_NICE,
#[cfg(any(target_os = "linux", target_os = "android"))]
RLIMIT_RTPRIO = libc::RLIMIT_RTPRIO,
#[cfg(any(target_os = "linux", target_os = "android"))]
RLIMIT_RTTIME = libc::RLIMIT_RTTIME,
#[cfg(any(target_os = "linux", target_os = "android"))]
RLIMIT_SIGPENDING = libc::RLIMIT_SIGPENDING,
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are more resources on non-Linux platforms, such as RLIMIT_KQUEUES, RLIMIT_NPTS, RLIMIT_SBSIZE, and RLIMIT_SWAP.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


#[inline]
fn rlim_to_option(rlim: rlim_t) -> Option<rlim_t> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there not a better API to do this? I would think this would be a common enough idiom that there's a function somewhere in the Rust API to do this already.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've changed it to a rust-style ternary expression. Option.filter would work, but is nightly only.

match rlim {
RLIM_INFINITY => None,
rlim => Some(rlim),
}
}

pub fn getrlimit(resource: Resource) -> Result<(Option<rlim_t>, Option<rlim_t>)> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs a doccomment, should have an example as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

let mut rlim: rlimit = unsafe { mem::uninitialized() };
let res = unsafe { libc::getrlimit(resource as c_int, &mut rlim as *mut _) };
Errno::result(res)?;
Ok((rlim_to_option(rlim.rlim_cur), rlim_to_option(rlim.rlim_max)))
}

pub fn setrlimit(resource: Resource, limit: (Option<rlim_t>, Option<rlim_t>)) -> Result<()> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a fan of this API because it's hard to know what limit means. I'd make this take a soft_limit and a hard_limit which are both Option<rlim_t>s so it's more explicit.

Additionally this should have doccomments and an example showing how this would be used (can be same as the one for getrlimit.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've changed the api to

setrlimit(resource: Resource, soft_limit: Option<rlim_t>, hard_limit: Option<rlim_t>) -> Result<()>

I'd prefer to delay documentation until the api itself is approved.

let mut rlim: rlimit = unsafe { mem::uninitialized() };
rlim.rlim_cur = limit.0.unwrap_or(RLIM_INFINITY);
rlim.rlim_max = limit.1.unwrap_or(RLIM_INFINITY);

let res = unsafe { libc::setrlimit(resource as c_int, &rlim as *const _) };
Errno::result(res).map(drop)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please do Errno::result(res).map(|_| ()) as it's more clear about what it's actually doing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be map(|_| ()).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

}
1 change: 1 addition & 0 deletions test/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ mod test_fcntl;
mod test_mq;
mod test_net;
mod test_nix_path;
mod test_resource;
mod test_poll;
mod test_pty;
#[cfg(any(target_os = "linux", target_os = "android"))]
Expand Down
22 changes: 22 additions & 0 deletions test/test_resource.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use nix::sys::resource::{Resource, getrlimit, setrlimit};

#[test]
pub fn test_resource_limits() {
let mut limit = getrlimit(Resource::RLIMIT_STACK).unwrap();
assert!(limit.0 != limit.1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assertion need not hold universally. On FreeBSD for example, the default hard limits and soft limits seem to be identical.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


let orig_limit = limit;

limit.0 = limit.1;
setrlimit(Resource::RLIMIT_STACK, limit).unwrap();

let limit2 = getrlimit(Resource::RLIMIT_STACK).unwrap();
assert_eq!(limit.0, limit2.0);
assert_eq!(limit.1, limit2.1);

setrlimit(Resource::RLIMIT_STACK, orig_limit).unwrap();

let final_limit = getrlimit(Resource::RLIMIT_STACK).unwrap();
assert_eq!(orig_limit.0, final_limit.0);
assert_eq!(orig_limit.1, final_limit.1);
}