1pub enum Outcome {
17 LimitRaised {
19 from: u64,
21 to: u64,
23 },
24 Unsupported,
26}
27
28#[derive(Debug, thiserror::Error)]
30pub enum Error {
31 #[error("Failed to call sysctl to get max supported value configured in sysctl: {0}")]
33 #[cfg(any(target_os = "macos", target_os = "ios"))]
34 FailedToCallSysctl(std::io::Error),
35 #[error("Failed to get current limit: {0}")]
37 FailedToGetLimit(std::io::Error),
38 #[error("Failed to set new limit ({from}->{to}): {error}")]
40 FailedToSetLimit {
41 from: u64,
43 to: u64,
45 error: std::io::Error,
47 },
48}
49
50#[cfg(any(target_os = "macos", target_os = "ios"))]
58#[allow(clippy::useless_conversion, non_camel_case_types)]
59pub fn raise_fd_limit() -> Result<Outcome, Error> {
60 use std::cmp;
61 use std::io;
62 use std::mem::size_of_val;
63 use std::ptr::null_mut;
64
65 unsafe {
66 static CTL_KERN: libc::c_int = 1;
67 static KERN_MAXFILESPERPROC: libc::c_int = 29;
68
69 let mut mib: [libc::c_int; 2] = [CTL_KERN, KERN_MAXFILESPERPROC];
75 let mut maxfiles: libc::c_int = 0;
76 let mut size: libc::size_t = size_of_val(&maxfiles) as libc::size_t;
77 if libc::sysctl(&mut mib[0], 2, &mut maxfiles as *mut _ as *mut _, &mut size, null_mut(), 0)
78 != 0
79 {
80 return Err(Error::FailedToCallSysctl(io::Error::last_os_error()));
81 }
82
83 let mut rlim = libc::rlimit { rlim_cur: 0, rlim_max: 0 };
85 if libc::getrlimit(libc::RLIMIT_NOFILE, &mut rlim) != 0 {
86 return Err(Error::FailedToGetLimit(io::Error::last_os_error()));
87 }
88
89 let old_value = rlim.rlim_cur;
90
91 rlim.rlim_cur = cmp::min(maxfiles as libc::rlim_t, rlim.rlim_max);
94
95 if libc::setrlimit(libc::RLIMIT_NOFILE, &rlim) != 0 {
97 return Err(Error::FailedToSetLimit {
98 from: old_value.into(),
99 to: rlim.rlim_cur.into(),
100 error: io::Error::last_os_error(),
101 });
102 }
103
104 Ok(Outcome::LimitRaised { from: old_value.into(), to: rlim.rlim_cur.into() })
105 }
106}
107
108#[cfg(target_os = "linux")]
111#[allow(clippy::useless_conversion, non_camel_case_types)]
112pub fn raise_fd_limit() -> Result<Outcome, Error> {
113 use std::io;
114
115 unsafe {
116 let mut rlim = libc::rlimit { rlim_cur: 0, rlim_max: 0 };
118 if libc::getrlimit(libc::RLIMIT_NOFILE, &mut rlim) != 0 {
119 return Err(Error::FailedToGetLimit(io::Error::last_os_error()));
120 }
121
122 let old_value = rlim.rlim_cur;
123
124 rlim.rlim_cur = rlim.rlim_max;
126
127 if libc::setrlimit(libc::RLIMIT_NOFILE, &rlim) != 0 {
129 return Err(Error::FailedToSetLimit {
130 from: old_value.into(),
131 to: rlim.rlim_cur.into(),
132 error: io::Error::last_os_error(),
133 });
134 }
135
136 Ok(Outcome::LimitRaised { from: old_value.into(), to: rlim.rlim_cur.into() })
137 }
138}
139
140#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "linux")))]
142pub fn raise_fd_limit() -> Result<Outcome, Error> {
143 Ok(Outcome::Unsupported)
144}