Skip to content

Commit

Permalink
Merge pull request #10 from nazar-pc/error-instead-of-panic
Browse files Browse the repository at this point in the history
Error instead of panic
  • Loading branch information
bkchr authored Nov 9, 2023
2 parents 5ca49cf + 6a253ce commit eee618f
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 39 deletions.
4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
[package]
name = "fdlimit"
version = "0.2.1"
version = "0.3.0"
authors = ["Parity Technologies<admin@parity.io>"]
edition = "2021"
license = "Apache-2.0"
description = "Utility crate for raising file descriptors limit for OSX and Linux"
repository = "https://github.com/paritytech/fdlimit"

[dependencies]
libc = "0.2"
thiserror = "1.0.50"
104 changes: 66 additions & 38 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,51 @@
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate libc;
/// Outcome of raising file descriptor resource limit
pub enum Outcome {
/// Limit was raised successfully
LimitRaised {
/// Previous limit (likely soft limit)
from: u64,
/// New limit (likely hard limit)
to: u64,
},
/// Raising limit is not supported on this platform
Unsupported,
}

/// Errors that happen when trying to raise file descriptor resource limit
#[derive(Debug, thiserror::Error)]
pub enum Error {
/// Failed to call sysctl to get max supported value configured in sysctl
#[error("Failed to call sysctl to get max supported value configured in sysctl: {0}")]
#[cfg(any(target_os = "macos", target_os = "ios"))]
FailedToCallSysctl(std::io::Error),
/// Failed to get current limit
#[error("Failed to get current limit: {0}")]
FailedToGetLimit(std::io::Error),
/// Failed to set new limit
#[error("Failed to set new limit ({from}->{to}): {error}")]
FailedToSetLimit {
/// Current limit
from: u64,
/// New desired limit
to: u64,
/// Low level OS error
error: std::io::Error,
},
}

/// Raise the soft open file descriptor resource limit to the smaller of the
/// kernel limit and the hard resource limit.
///
/// Returns [`Some`] with the new limit.
///
/// # Panics
///
/// Panics if [`libc::sysctl`], [`libc::getrlimit`] or [`libc::setrlimit`]
/// fail.
///
/// darwin_fd_limit exists to work around an issue where launchctl on Mac OS X
/// defaults the rlimit maxfiles to 256/unlimited. The default soft limit of 256
/// ends up being far too low for our multithreaded scheduler testing, depending
/// on the number of cores available.
#[cfg(any(target_os = "macos", target_os = "ios"))]
#[allow(non_camel_case_types)]
pub fn raise_fd_limit() -> Option<u64> {
#[allow(clippy::useless_conversion, non_camel_case_types)]
pub fn raise_fd_limit() -> Result<Outcome, Error> {
use std::cmp;
use std::io;
use std::mem::size_of_val;
Expand All @@ -48,69 +74,71 @@ pub fn raise_fd_limit() -> Option<u64> {
let mut mib: [libc::c_int; 2] = [CTL_KERN, KERN_MAXFILESPERPROC];
let mut maxfiles: libc::c_int = 0;
let mut size: libc::size_t = size_of_val(&maxfiles) as libc::size_t;
if libc::sysctl(&mut mib[0], 2, &mut maxfiles as *mut _ as *mut _, &mut size,
null_mut(), 0) != 0 {
let err = io::Error::last_os_error();
panic!("raise_fd_limit: error calling sysctl: {}", err);
if libc::sysctl(&mut mib[0], 2, &mut maxfiles as *mut _ as *mut _, &mut size, null_mut(), 0)
!= 0
{
return Err(Error::FailedToCallSysctl(io::Error::last_os_error()));
}

// Fetch the current resource limits
let mut rlim = libc::rlimit{rlim_cur: 0, rlim_max: 0};
let mut rlim = libc::rlimit { rlim_cur: 0, rlim_max: 0 };
if libc::getrlimit(libc::RLIMIT_NOFILE, &mut rlim) != 0 {
let err = io::Error::last_os_error();
panic!("raise_fd_limit: error calling getrlimit: {}", err);
return Err(Error::FailedToGetLimit(io::Error::last_os_error()));
}

let old_value = rlim.rlim_cur;

// Bump the soft limit to the smaller of kern.maxfilesperproc and the hard
// limit
rlim.rlim_cur = cmp::min(maxfiles as libc::rlim_t, rlim.rlim_max);

// Set our newly-increased resource limit
if libc::setrlimit(libc::RLIMIT_NOFILE, &rlim) != 0 {
let err = io::Error::last_os_error();
panic!("raise_fd_limit: error calling setrlimit: {}", err);
return Err(Error::FailedToSetLimit {
from: old_value.into(),
to: rlim.rlim_cur.into(),
error: io::Error::last_os_error(),
});
}

Some(rlim.rlim_cur)
Ok(Outcome::LimitRaised { from: old_value.into(), to: rlim.rlim_cur.into() })
}
}

/// Raise the soft open file descriptor resource limit to the hard resource
/// limit.
///
/// Returns [`Some`] with the new limit.
///
/// # Panics
///
/// Panics if [`libc::getrlimit`] or [`libc::setrlimit`] fail.
#[cfg(any(target_os = "linux"))]
#[allow(non_camel_case_types)]
pub fn raise_fd_limit() -> Option<u64> {
#[cfg(target_os = "linux")]
#[allow(clippy::useless_conversion, non_camel_case_types)]
pub fn raise_fd_limit() -> Result<Outcome, Error> {
use std::io;

unsafe {
// Fetch the current resource limits
let mut rlim = libc::rlimit{rlim_cur: 0, rlim_max: 0};
let mut rlim = libc::rlimit { rlim_cur: 0, rlim_max: 0 };
if libc::getrlimit(libc::RLIMIT_NOFILE, &mut rlim) != 0 {
let err = io::Error::last_os_error();
panic!("raise_fd_limit: error calling getrlimit: {}", err);
return Err(Error::FailedToGetLimit(io::Error::last_os_error()));
}

let old_value = rlim.rlim_cur;

// Set soft limit to hard imit
rlim.rlim_cur = rlim.rlim_max;

// Set our newly-increased resource limit
if libc::setrlimit(libc::RLIMIT_NOFILE, &rlim) != 0 {
let err = io::Error::last_os_error();
panic!("raise_fd_limit: error calling setrlimit: {}", err);
return Err(Error::FailedToSetLimit {
from: old_value.into(),
to: rlim.rlim_cur.into(),
error: io::Error::last_os_error(),
});
}

Some(rlim.rlim_cur.into())
Ok(Outcome::LimitRaised { from: old_value.into(), to: rlim.rlim_cur.into() })
}
}

/// Returns [`None`].
/// Does nothing on unsupported platform
#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "linux")))]
pub fn raise_fd_limit() -> Option<u64> {
None
pub fn raise_fd_limit() -> Result<Outcome, Error> {
Ok(Outcome::Unsupported)
}

0 comments on commit eee618f

Please sign in to comment.