diff --git a/src/api.rs b/src/api.rs index 30c117a..5700e3a 100644 --- a/src/api.rs +++ b/src/api.rs @@ -60,6 +60,7 @@ use crate::{ render::util::snapshot::capture_snapshots_on_output, state::{State, WithState}, tag::{Tag, TagId}, + util::restore_nofile_rlimit, }; type ResponseStream = Pin> + Send>>; @@ -587,22 +588,30 @@ impl process_service_server::ProcessService for ProcessService { } } - let Ok(mut child) = tokio::process::Command::new(OsString::from(arg0.clone())) - .stdin(match has_callback { - true => Stdio::piped(), - false => Stdio::null(), - }) - .stdout(match has_callback { - true => Stdio::piped(), - false => Stdio::null(), - }) - .stderr(match has_callback { - true => Stdio::piped(), - false => Stdio::null(), - }) - .args(command) - .spawn() - else { + let mut cmd = tokio::process::Command::new(OsString::from(arg0.clone())); + + cmd.stdin(match has_callback { + true => Stdio::piped(), + false => Stdio::null(), + }) + .stdout(match has_callback { + true => Stdio::piped(), + false => Stdio::null(), + }) + .stderr(match has_callback { + true => Stdio::piped(), + false => Stdio::null(), + }) + .args(command); + + unsafe { + cmd.pre_exec(|| { + restore_nofile_rlimit(); + Ok(()) + }); + } + + let Ok(mut child) = cmd.spawn() else { warn!("Tried to run {arg0}, but it doesn't exist",); return; }; diff --git a/src/lib.rs b/src/lib.rs index 3b0e08e..f642979 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,4 +13,5 @@ pub mod protocol; pub mod render; pub mod state; pub mod tag; +pub mod util; pub mod window; diff --git a/src/main.rs b/src/main.rs index a12d36a..c2e5ea2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,6 +18,7 @@ use pinnacle::{ cli::{self, Cli}, config::{get_config_dir, parse_metaconfig, Metaconfig}, state::State, + util::increase_nofile_rlimit, }; use smithay::reexports::{calloop::EventLoop, rustix::process::geteuid}; use tracing::{error, info, warn}; @@ -63,6 +64,8 @@ async fn main() -> anyhow::Result<()> { info!("Starting Pinnacle (commit {})", env!("VERGEN_GIT_SHA")); + increase_nofile_rlimit(); + set_log_panic_hook(); let Some(cli) = Cli::parse_and_prompt() else { diff --git a/src/util.rs b/src/util.rs new file mode 100644 index 0000000..dfe4e78 --- /dev/null +++ b/src/util.rs @@ -0,0 +1,34 @@ +use std::sync::atomic::{AtomicU64, Ordering}; + +use smithay::reexports::rustix::process::{getrlimit, setrlimit, Resource, Rlimit}; +use tracing::warn; + +static NOFILE_RLIMIT_CURRENT: AtomicU64 = AtomicU64::new(0); +static NOFILE_RLIMIT_MAXIMUM: AtomicU64 = AtomicU64::new(0); + +pub fn increase_nofile_rlimit() { + let mut limits = getrlimit(Resource::Nofile); + + NOFILE_RLIMIT_CURRENT.store(limits.current.unwrap_or(0), Ordering::SeqCst); + NOFILE_RLIMIT_MAXIMUM.store(limits.maximum.unwrap_or(0), Ordering::SeqCst); + + limits.current = limits.maximum; + + if let Err(err) = setrlimit(Resource::Nofile, limits) { + warn!("Failed to raise nofile limit: {err}"); + } +} + +pub fn restore_nofile_rlimit() { + let current = NOFILE_RLIMIT_CURRENT.load(Ordering::SeqCst); + let maximum = NOFILE_RLIMIT_MAXIMUM.load(Ordering::SeqCst); + + let limits = Rlimit { + current: (current > 0).then_some(current), + maximum: (maximum > 0).then_some(maximum), + }; + + if let Err(err) = setrlimit(Resource::Nofile, limits) { + warn!("Failed to restore nofile limit: {err}"); + } +}