-
Notifications
You must be signed in to change notification settings - Fork 674
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add getrlimit(2) and setrlimit(2) #879
Conversation
src/sys/resource.rs
Outdated
#[cfg(any(target_os = "linux", | ||
target_os = "openbsd", | ||
target_os = "netbsd", | ||
target_os = "bitrig"))] |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done, removed the import.
src/sys/resource.rs
Outdated
|
||
#[derive(Clone, Copy, PartialEq, Eq, Debug)] | ||
#[repr(i32)] | ||
pub enum Resource { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
src/sys/resource.rs
Outdated
} | ||
} | ||
|
||
pub fn getrlimit(resource: Resource) -> Result<(Option<rlim_t>, Option<rlim_t>)> { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
src/sys/resource.rs
Outdated
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<()> { |
There was a problem hiding this comment.
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
.
There was a problem hiding this comment.
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.
src/sys/resource.rs
Outdated
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) |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
src/sys/resource.rs
Outdated
RLIMIT_STACK = libc::RLIMIT_STACK, | ||
RLIMIT_AS = libc::RLIMIT_AS, | ||
// BSDs and Linux | ||
#[cfg(all(unix, not(target_os = "solaris")))] |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
src/sys/resource.rs
Outdated
} | ||
|
||
#[inline] | ||
fn rlim_to_option(rlim: rlim_t) -> Option<rlim_t> { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
src/sys/resource.rs
Outdated
#[cfg(all(unix, not(target_os = "solaris")))] | ||
RLIMIT_RSS = libc::RLIMIT_RSS, | ||
// Linux-only | ||
#[cfg(any(target_os = "linux", target_os = "android"))] |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
src/sys/resource.rs
Outdated
RLIMIT_NPROC = libc::RLIMIT_NPROC, | ||
#[cfg(all(unix, not(target_os = "solaris")))] | ||
RLIMIT_RSS = libc::RLIMIT_RSS, | ||
// Linux-only |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Android and Linux only"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
test/test_resource.rs
Outdated
#[test] | ||
pub fn test_resource_limits() { | ||
let mut limit = getrlimit(Resource::RLIMIT_STACK).unwrap(); | ||
assert!(limit.0 != limit.1); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
src/sys/resource.rs
Outdated
use std::mem; | ||
|
||
use libc::{self, c_int}; | ||
pub use libc::{rlimit, rlim_t, RLIM_INFINITY}; |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
src/sys/resource.rs
Outdated
target_os = "openbsd", | ||
target_os = "netbsd", | ||
target_os = "bitrig"))] | ||
pub use libc::{RLIM_SAVED_CUR, RLIM_SAVED_MAX}; |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done, removed the import.
src/sys/resource.rs
Outdated
RLIMIT_RTTIME = libc::RLIMIT_RTTIME, | ||
#[cfg(any(target_os = "linux", target_os = "android"))] | ||
RLIMIT_SIGPENDING = libc::RLIMIT_SIGPENDING, | ||
} |
There was a problem hiding this comment.
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
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm happy with the API now.
src/sys/resource.rs
Outdated
match rlim { | ||
RLIM_INFINITY => None, | ||
rlim => Some(rlim), | ||
// Non-Linux |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment makes it sound like these symbols are available everywhere except Linux.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed to // Available on some BSD
src/sys/resource.rs
Outdated
RLIMIT_KQUEUES, | ||
#[cfg(target_os = "freebsd")] | ||
RLIMIT_NPTS, | ||
#[cfg(target_os = "freebsd")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RLIMIT_SBSIZE
is also available on Dragonfly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
test/test_resource.rs
Outdated
let mut limit = getrlimit(Resource::RLIMIT_STACK).unwrap(); | ||
assert!(limit.0 != limit.1); | ||
let (mut soft_limit, hard_limit) = getrlimit(Resource::RLIMIT_STACK).unwrap(); | ||
let orig_limit = (soft_limit, hard_limit); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Your changes to the test do fix the previous failure, but the coverage isn't very good, since the soft and hard limits are often identical. How about setting RLIMIT_NOFILE
to a hard-coded value of 1024 if the current soft limit is unlimited, or the current softlimit - 1 otherwise?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we really need two tests? Does the stack test provide any extra coverage over the RLIMIT_NOFILE
test?
src/sys/resource.rs
Outdated
/// # Examples | ||
/// | ||
/// ``` | ||
/// use nix::sys::resource::{getrlimit, Resource}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the doc test, you should put a #
before the use
, fn main
, and final }
lines so they will be hidden from the documentation. Likewise, omit the blank line before main
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
src/sys/resource.rs
Outdated
/// # Parameters | ||
/// | ||
/// * `resource`: The [`Resource`] that we want to set the limits of. | ||
/// * `soft_limit`: The value that the kenrel enforces for the corresponding resource. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/kenrel/kernel
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
test/test_resource.rs
Outdated
setrlimit(Resource::RLIMIT_NOFILE, soft_limit, hard_limit).unwrap(); | ||
|
||
let (new_soft_limit, new_hard_limit) = getrlimit(Resource::RLIMIT_NOFILE).unwrap(); | ||
assert!(new_soft_limit != new_hard_limit); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be assert!(new_soft_limit, soft_limit)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
test/test_resource.rs
Outdated
let mut limit = getrlimit(Resource::RLIMIT_STACK).unwrap(); | ||
assert!(limit.0 != limit.1); | ||
let (mut soft_limit, hard_limit) = getrlimit(Resource::RLIMIT_STACK).unwrap(); | ||
let orig_limit = (soft_limit, hard_limit); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we really need two tests? Does the stack test provide any extra coverage over the RLIMIT_NOFILE
test?
src/sys/resource.rs
Outdated
libc_enum!{ | ||
#[repr(i32)] | ||
pub enum Resource { | ||
// POSIX |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please provide doc comments for every entry here to give users an understanding of what they mean.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
src/sys/resource.rs
Outdated
|
||
libc_enum!{ | ||
#[repr(i32)] | ||
pub enum Resource { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This enum needs a doccomment as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
src/sys/resource.rs
Outdated
|
||
/// Get the current processes resource limits | ||
/// | ||
/// A value of `None` corresponds to `RLIM_INFINITY`, which means there's no limit. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd just remove the RLIM_INFINITY
reference. For the user that implementation detail is completely hidden: "A value of None
indicates that there's no limit."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
src/sys/resource.rs
Outdated
/// | ||
/// ``` | ||
/// # use nix::sys::resource::{getrlimit, Resource}; | ||
/// # fn main() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You shouldn't need to declare main()
here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
src/sys/resource.rs
Outdated
rlim.rlim_max = hard_limit.unwrap_or(RLIM_INFINITY); | ||
|
||
let res = unsafe { libc::setrlimit(resource as c_int, &rlim as *const _) }; | ||
Errno::result(res).map(drop) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be map(|_| ())
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
src/sys/resource.rs
Outdated
pub fn getrlimit(resource: Resource) -> Result<(Option<rlim_t>, Option<rlim_t>)> { | ||
let mut rlim: rlimit = unsafe { mem::uninitialized() }; | ||
let res = unsafe { libc::getrlimit(resource as c_int, &mut rlim as *mut _) }; | ||
Errno::result(res).map(|_| { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ugly, but it works. Can you put a TODO
in here to switch over to that other API you mentioned once it hits stable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
test/test_resource.rs
Outdated
|
||
// make sure the soft limit and hard limit are not equal | ||
let soft_limit = match soft_limit { | ||
Some(nofile) => Some(nofile -1), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need a space after the -
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
use nix::sys::resource::{Resource, getrlimit, setrlimit}; | ||
|
||
#[test] | ||
pub fn test_resource_limits_nofile() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you summarize what this test is doing? Makes it easier to fix or modify them later.
src/sys/resource.rs
Outdated
/// # fn main() { | ||
/// let soft_limit = Some(1024); | ||
/// let hard_limit = None; | ||
/// setrlimit(Resource::RLIMIT_NOFILE, soft_limit, hard_limit).unwrap(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this a realistic use case auser might actually do? If not, we should try to find one more common to use as an example and provide a nice description of it before the codeblock.
} | ||
|
||
#[test] | ||
pub fn test_resource_limits_stack() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you provide some comments or a general summarizing comment here? It makes it easier for us reviewers to understand and to modify/fix them later.
I'm having trouble coming up with a cross plattform compatible test that is also a realistic test case. Could you suggest one? |
A test doesn't need to run on all platforms, though it's nice if it does. It'd be good to get at least a test working on one of our Tier 1 platforms so it'll run regularly in CI tho. |
/// [setrlimit(2)](https://linux.die.net/man/2/setrlimit) | ||
/// | ||
/// [`Resource`]: enum.Resource.html | ||
pub fn setrlimit(resource: Resource, soft_limit: Option<rlim_t>, hard_limit: Option<rlim_t>) -> Result<()> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I came in here to suggest changing this to
pub fn setrlimit<S=rlim_t, H=rlim_t>(resource: Resource, soft_limit: Option<rlim_t>, hard_limit: Option<rlim_t>) -> Result<()>
where S: Into<Option<rlim_t>>, H: Into<Option<rlim_t>> { // ...
playground example
to take advantage for the impl<T> From<T> for Option<T>
impl added in 1.12: rust-lang/rust#34828.
but it turns out we can't use default type params in functions on stable. There's a WG looking into this, so maybe we can open it up later this year. (This would allow setrlimit(RLIMIT_RSS, 1024 * 1024, None)
without the Some
wrapping on the first arg.)
/// [`Resource`]: enum.Resource.html | ||
pub fn setrlimit(resource: Resource, soft_limit: Option<rlim_t>, hard_limit: Option<rlim_t>) -> Result<()> { | ||
let mut rlim: rlimit = unsafe { mem::uninitialized() }; | ||
rlim.rlim_cur = soft_limit.unwrap_or(RLIM_INFINITY); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer to leave this to the kernel.
@kpcyrd friendly pin on this. |
This issue is up for grabs if anybody is interested in it, but I might come back to it later. I'm currently using my own solution in the program I was working on when filing this PR. |
Implemented by #1302. |
This is a followup of #364 by @kamalmarhubi. The api has been changed to
(Option<rlim_t>, Option<rlim_t>)
to hide the rlim struct. This allows:Resolves #878.