aboutsummaryrefslogtreecommitdiff
path: root/src/platform
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-05-27 21:35:56 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-05-27 21:36:26 +0300
commit8e7317e223bcfe38281a71fb121b0b65aaab1a43 (patch)
tree23acae73320ee4c6a186fde9ee51146e9e23a005 /src/platform
parent3325304f89d56990f3134a3d01749e5de498725d (diff)
fix: raise macos server fd limit
refs #327
Diffstat (limited to 'src/platform')
-rw-r--r--src/platform/fallback.rs3
-rw-r--r--src/platform/linux.rs2
-rw-r--r--src/platform/macos.rs68
3 files changed, 73 insertions, 0 deletions
diff --git a/src/platform/fallback.rs b/src/platform/fallback.rs
index d7360f9b..42abfcb2 100644
--- a/src/platform/fallback.rs
+++ b/src/platform/fallback.rs
@@ -3,6 +3,9 @@ use std::path::PathBuf;
use super::{ClipboardImage, ForegroundJob, Signal};
/// Unsupported platform stub.
+pub fn raise_server_nofile_limit() {}
+
+/// Unsupported platform stub.
pub fn foreground_job(_child_pid: u32) -> Option<ForegroundJob> {
None
}
diff --git a/src/platform/linux.rs b/src/platform/linux.rs
index 2ea26559..046e72c7 100644
--- a/src/platform/linux.rs
+++ b/src/platform/linux.rs
@@ -9,6 +9,8 @@ use super::{
LimitedRead, Signal,
};
+pub fn raise_server_nofile_limit() {}
+
/// Collect the foreground terminal job for a given child PID.
pub fn foreground_job(child_pid: u32) -> Option<ForegroundJob> {
let tpgid = foreground_process_group_id(child_pid)?;
diff --git a/src/platform/macos.rs b/src/platform/macos.rs
index 3ff23251..ac0e160b 100644
--- a/src/platform/macos.rs
+++ b/src/platform/macos.rs
@@ -11,6 +11,53 @@ use super::{
};
const PROC_PGRP_ONLY: u32 = 2;
+const SERVER_NOFILE_LIMIT_TARGET: libc::rlim_t = 8192;
+
+pub fn raise_server_nofile_limit() {
+ match raise_nofile_limit(SERVER_NOFILE_LIMIT_TARGET) {
+ Ok(None) => {}
+ Ok(Some((previous, target))) => {
+ tracing::info!(previous, target, "raised server file descriptor soft limit")
+ }
+ Err(err) => tracing::warn!(err = %err, "failed to raise server file descriptor limit"),
+ }
+}
+
+fn raise_nofile_limit(
+ target: libc::rlim_t,
+) -> std::io::Result<Option<(libc::rlim_t, libc::rlim_t)>> {
+ let mut limit = std::mem::MaybeUninit::<libc::rlimit>::uninit();
+ if unsafe { libc::getrlimit(libc::RLIMIT_NOFILE, limit.as_mut_ptr()) } != 0 {
+ return Err(std::io::Error::last_os_error());
+ }
+
+ let mut limit = unsafe { limit.assume_init() };
+ let Some(target) = target_nofile_soft_limit(limit.rlim_cur, limit.rlim_max, target) else {
+ return Ok(None);
+ };
+
+ let previous = limit.rlim_cur;
+ limit.rlim_cur = target;
+ if unsafe { libc::setrlimit(libc::RLIMIT_NOFILE, &limit) } != 0 {
+ return Err(std::io::Error::last_os_error());
+ }
+
+ Ok(Some((previous, target)))
+}
+
+fn target_nofile_soft_limit(
+ current: libc::rlim_t,
+ hard: libc::rlim_t,
+ target: libc::rlim_t,
+) -> Option<libc::rlim_t> {
+ let target = if hard == libc::RLIM_INFINITY {
+ target
+ } else {
+ target.min(hard)
+ };
+
+ (current < target).then_some(target)
+}
/// Collect the foreground terminal job for a given child PID.
pub fn foreground_job(child_pid: u32) -> Option<ForegroundJob> {
@@ -670,6 +717,27 @@ pub fn process_exists(pid: u32) -> bool {
mod tests {
use super::*;
+ #[test]
+ fn nofile_target_raises_low_soft_limit_to_cap_when_hard_is_unlimited() {
+ assert_eq!(
+ target_nofile_soft_limit(256, libc::RLIM_INFINITY, 8192),
+ Some(8192)
+ );
+ }
+
+ #[test]
+ fn nofile_target_respects_finite_hard_limit() {
+ assert_eq!(target_nofile_soft_limit(256, 4096, 8192), Some(4096));
+ }
+
+ #[test]
+ fn nofile_target_does_not_lower_existing_soft_limit() {
+ assert_eq!(
+ target_nofile_soft_limit(16_384, libc::RLIM_INFINITY, 8192),
+ None
+ );
+ }
+
fn build_procargs2(exec_path: &str, argv: &[&str], env: &[&str]) -> Vec<u8> {
let mut buf = Vec::new();
buf.extend_from_slice(&(argv.len() as i32).to_ne_bytes());