Skip to content
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

Closed
wants to merge 11 commits into from
Closed
Show file tree
Hide file tree
Changes from 3 commits
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
58 changes: 56 additions & 2 deletions src/sys/resource.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//! Configure the process resource limits.
use std::mem;

use libc::{self, c_int, rlimit, RLIM_INFINITY};
Expand Down Expand Up @@ -39,18 +40,43 @@ libc_enum!{
#[cfg(any(target_os = "android", target_os = "linux"))]
RLIMIT_SIGPENDING,

// Non-Linux
// Available on some BSD
#[cfg(target_os = "freebsd")]
RLIMIT_KQUEUES,
#[cfg(target_os = "freebsd")]
RLIMIT_NPTS,
#[cfg(target_os = "freebsd")]
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
RLIMIT_SBSIZE,
#[cfg(target_os = "freebsd")]
RLIMIT_SWAP,
}
}

/// Get the current processes resource limits
///
/// A value of `None` corresponds to `RLIM_INFINITY`, which means there's no limit.
Copy link
Contributor

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."

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

///
/// # Parameters
///
/// * `resource`: The [`Resource`] that we want to get the limits of.
///
/// # Examples
///
/// ```
/// use nix::sys::resource::{getrlimit, Resource};
Copy link
Member

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.

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

///
/// fn main() {
/// let (soft_limit, hard_limit) = getrlimit(Resource::RLIMIT_NOFILE).unwrap();
/// println!("current soft_limit: {:?}", soft_limit);
/// println!("current hard_limit: {:?}", hard_limit);
/// }
/// ```
///
/// # References
///
/// [getrlimit(2)](https://linux.die.net/man/2/getrlimit)
///
/// [`Resource`]: enum.Resource.html
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 _) };
Expand All @@ -60,6 +86,34 @@ pub fn getrlimit(resource: Resource) -> Result<(Option<rlim_t>, Option<rlim_t>)>
})
}

/// Set the current processes resource limits
///
/// A value of `None` corresponds to `RLIM_INFINITY`, which means there's no limit.
Copy link
Contributor

Choose a reason for hiding this comment

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

Same as above, don't bother mentioning RLIM_INFINITY

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

///
/// # Parameters
///
/// * `resource`: The [`Resource`] that we want to set the limits of.
/// * `soft_limit`: The value that the kenrel enforces for the corresponding resource.
Copy link
Member

Choose a reason for hiding this comment

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

s/kenrel/kernel

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

/// * `hard_limit`: The ceiling for the soft limit. Must be lower or equal to the current hard limit
/// for non-root users.
///
/// # Examples
///
/// ```no_run
/// use nix::sys::resource::{setrlimit, Resource};
///
/// fn main() {
/// let soft_limit = Some(1024);
/// let hard_limit = None;
/// setrlimit(Resource::RLIMIT_NOFILE, soft_limit, hard_limit).unwrap();
/// }
/// ```
///
/// # References
///
/// [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<()> {
Copy link
Member

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.)

let mut rlim: rlimit = unsafe { mem::uninitialized() };
rlim.rlim_cur = soft_limit.unwrap_or(RLIM_INFINITY);
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this be checked to be less than rlim_max or should that be deferred to the setrlimit call?

Copy link
Member

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.

Expand Down
17 changes: 16 additions & 1 deletion test/test_resource.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,22 @@
use nix::sys::resource::{Resource, getrlimit, setrlimit};

#[test]
pub fn test_resource_limits() {
pub fn test_resource_limits_nofile() {
Copy link
Contributor

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.

let (soft_limit, hard_limit) = getrlimit(Resource::RLIMIT_NOFILE).unwrap();

// make sure the soft limit and hard limit are not equal
let soft_limit = match soft_limit {
Some(nofile) => Some(nofile -1),
Copy link
Contributor

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 -

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

None => Some(1024),
};
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);
Copy link
Member

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)

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

}

#[test]
pub fn test_resource_limits_stack() {
Copy link
Contributor

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.

let (mut soft_limit, hard_limit) = getrlimit(Resource::RLIMIT_STACK).unwrap();
let orig_limit = (soft_limit, hard_limit);
Copy link
Member

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?

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
Member

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?


Expand Down