1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
// Copyright 2016-2020 Parity Technologies (UK) Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/// 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.
///
/// 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(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;
use std::ptr::null_mut;
unsafe {
static CTL_KERN: libc::c_int = 1;
static KERN_MAXFILESPERPROC: libc::c_int = 29;
// The strategy here is to fetch the current resource limits, read the
// kern.maxfilesperproc sysctl value, and bump the soft resource limit for
// maxfiles up to the sysctl value.
// Fetch the kern.maxfilesperproc value
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
{
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 };
if libc::getrlimit(libc::RLIMIT_NOFILE, &mut rlim) != 0 {
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 {
return Err(Error::FailedToSetLimit {
from: old_value.into(),
to: rlim.rlim_cur.into(),
error: io::Error::last_os_error(),
});
}
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.
#[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 };
if libc::getrlimit(libc::RLIMIT_NOFILE, &mut rlim) != 0 {
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 {
return Err(Error::FailedToSetLimit {
from: old_value.into(),
to: rlim.rlim_cur.into(),
error: io::Error::last_os_error(),
});
}
Ok(Outcome::LimitRaised { from: old_value.into(), to: rlim.rlim_cur.into() })
}
}
/// Does nothing on unsupported platform
#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "linux")))]
pub fn raise_fd_limit() -> Result<Outcome, Error> {
Ok(Outcome::Unsupported)
}