Skip to content

Add getrlimit(2) and setrlimit(2) #364

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

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all 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
2 changes: 2 additions & 0 deletions src/sys/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ pub mod memfd;
#[cfg(not(any(target_os = "ios", target_os = "freebsd", target_os = "dragonfly")))]
pub mod ioctl;

pub mod resource;

#[cfg(any(target_os = "linux", target_os = "android"))]
pub mod sendfile;

Expand Down
54 changes: 54 additions & 0 deletions src/sys/resource.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
use std::mem;

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

Choose a reason for hiding this comment

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

I think these should be reexported, but I'm not sure if we are consistently doing that.

Copy link
Contributor

Choose a reason for hiding this comment

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

What about RLIM_SAVED_CUR and RLIM_SAVED_MAX?

Why don't we wrap rlimit and provide proper accessor methods? I admit that it would be purely cosmetic in this case, as far as I can see.

Copy link
Member Author

Choose a reason for hiding this comment

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

forgotten! fixed.

Copy link
Contributor

Choose a reason for hiding this comment

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

What about the rlimit wrapper?

Copy link
Member Author

Choose a reason for hiding this comment

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

oh I was deciding not to do that since we aren't doing anything with the type. I wanted it to be easy to specify inline, eg

setrlimit(RLIMIT_STACK, rlimit { rlim_cur: 1024*1024, rlim_max: RLIM_INFINITY }).unwrap()

Copy link
Contributor

Choose a reason for hiding this comment

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

What about ResourceLimit::new(1024 * 1024, RLIM_INFINITY) ?

#[cfg(any(target_os = "linux",
target_os = "openbsd",
target_os = "netbsd",
target_os = "bitrig"))]
pub use libc::{RLIM_SAVED_CUR, RLIM_SAVED_MAX};

use {Errno, Result};

#[repr(i32)]
Copy link
Contributor

Choose a reason for hiding this comment

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

Using the type i32 here is dangerous. Who says that the constants are represented by 32bit integers on all (current and future) platforms?

I got around that in my pull request by using the default (isize) and casting the constants to isize in the enumeration, for example: RLIMIT_CORE = libc::RLIMIT_CORE as isize.

I would prefer to write #[repr(libc::c_int)] or whatever type is used for these constants at the moment in libc. But even that can differ from platform to platform.

Is there a way to conditionalize the repr line on platforms? We certainly can conditionalise the whole enumeration definition on the platform, but that is a lot of repetition, though that certainly can be dealt with using macros.

Copy link
Member Author

Choose a reason for hiding this comment

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

Is there a way to conditionalize the repr line on platforms?

This should work:

#[cfg_attr(target_os = "linux", repr(i32))]
#[cfg_attr(target_os = "some_other", repr(i16))]
pub enum Resource {
    ...
}

Copy link
Member Author

@kamalmarhubi kamalmarhubi Apr 30, 2016

Choose a reason for hiding this comment

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

Also I kind of answered this in #362 (comment) before seeing the question.

pub enum Resource {
Copy link
Member Author

Choose a reason for hiding this comment

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

should this be Resource or Rlimit / RLimit?

Copy link
Member Author

Choose a reason for hiding this comment

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

@fiveop thoughts? since you added the convention on enums...

Copy link
Contributor

Choose a reason for hiding this comment

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

I would prefer Resource, because it very clearly expresses what it stands for.

Copy link
Member

Choose a reason for hiding this comment

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

Resource as a name still feels a little off give the values in the enum. You are not really getting the rlimit of a resource, you are getting the value of a specific resource limit in the system (one "resource" may have multiple related limits).

I'm not completely sold on this, but I could see naming the enum ResourceLimit and allowing get/set on the limit. E.g.

let limit =  ResourceLimit::RLIMIT_STACK.get().unwrap();
ResourceLimit::RLIMIT_STACK.set(limit).unwrap();

Copy link
Member Author

Choose a reason for hiding this comment

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

yeah I thought of this kind of approach but I don't know yet how I feel about going so far from the C API.

In related news: I just created https://github.com/nix-rust/rfcs and will create RFC 0000 soon (probably tomorrow) to bootstrap the process. Then we'll have a good place to discuss stuff like this.

Copy link
Contributor

Choose a reason for hiding this comment

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

If we add the get and set methods to the type, the name ResourceLimit does make more sense. However, if we don't do that, the variants of the enum actually represent the Resource, whose limit is set/get by the methods setrlimit, getrlimit.

The more I think about it, the more I like @posborne's proposal.

// 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")))]
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
#[cfg(any(target_os = "linux", target_os = "android"))]
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,
}

pub fn getrlimit(resource: Resource) -> Result<rlimit> {
let mut rlim = unsafe { mem::uninitialized() };
let res = unsafe { libc::getrlimit(resource as c_int, &mut rlim as *mut _) };
Errno::result(res).map(|_| rlim)
}

pub fn setrlimit(resource: Resource, rlim: rlimit) -> Result<()> {
let res = unsafe { libc::setrlimit(resource as c_int, &rlim as *const _) };
Errno::result(res).map(drop)
}
1 change: 1 addition & 0 deletions test/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ mod sys;
mod test_fcntl;
mod test_net;
mod test_nix_path;
mod test_resource;
#[cfg(any(target_os = "linux", target_os = "android"))]
mod test_sendfile;
mod test_stat;
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.rlim_cur != limit.rlim_max);

let orig_limit = limit;

limit.rlim_cur = limit.rlim_max;
setrlimit(Resource::RLIMIT_STACK, limit).unwrap();

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

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

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