Detach Child process to avoid zombie processes

This makes use of the common double-fork behavior to prevent
spawning zombie processes every time a URL is clicked.
This commit is contained in:
Vineeth Sagar 2018-12-07 03:08:34 +05:30 committed by Christian Duerr
parent f57bd6e12f
commit cadbb86eb7
3 changed files with 34 additions and 39 deletions

View File

@ -26,6 +26,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fixed a bad type conversion which could cause underflow on a window resize - Fixed a bad type conversion which could cause underflow on a window resize
- Alacritty now spawns a login shell on macOS, as with Terminal.app and iTerm2 - Alacritty now spawns a login shell on macOS, as with Terminal.app and iTerm2
- Fixed zombie processes sticking around after launching URLs
## Version 0.2.3 ## Version 0.2.3

View File

@ -20,10 +20,7 @@
//! determine what to do when a non-modifier key is pressed. //! determine what to do when a non-modifier key is pressed.
use std::borrow::Cow; use std::borrow::Cow;
use std::mem; use std::mem;
use std::process::Command;
use std::time::Instant; use std::time::Instant;
#[cfg(not(windows))]
use std::os::unix::process::CommandExt;
use copypasta::{Clipboard, Load, Buffer as ClipboardBuffer}; use copypasta::{Clipboard, Load, Buffer as ClipboardBuffer};
use glutin::{ElementState, MouseButton, TouchPhase, MouseScrollDelta, ModifiersState, KeyboardInput}; use glutin::{ElementState, MouseButton, TouchPhase, MouseScrollDelta, ModifiersState, KeyboardInput};
@ -35,6 +32,7 @@ use index::{Line, Column, Side, Point};
use term::SizeInfo; use term::SizeInfo;
use term::mode::TermMode; use term::mode::TermMode;
use util::fmt::Red; use util::fmt::Red;
use util::start_daemon;
pub const FONT_SIZE_STEP: f32 = 0.5; pub const FONT_SIZE_STEP: f32 = 0.5;
@ -239,26 +237,9 @@ impl Action {
Action::Command(ref program, ref args) => { Action::Command(ref program, ref args) => {
trace!("running command: {} {:?}", program, args); trace!("running command: {} {:?}", program, args);
#[cfg(not(windows))] match start_daemon(program, args) {
let spawned = Command::new(program) Ok(_) => {
.args(args) debug!("spawned new proc");
.before_exec(|| {
// Detach forked process from Alacritty. This will cause
// init or whatever to clean up child processes for us.
unsafe { ::libc::daemon(1, 0); }
Ok(())
})
.spawn();
#[cfg(windows)]
let spawned = Command::new(program)
.args(args)
.spawn();
match spawned
{
Ok(child) => {
debug!("spawned new proc with pid: {}", child.id());
}, },
Err(err) => { Err(err) => {
warn!("couldn't run command: {}", err); warn!("couldn't run command: {}", err);
@ -557,7 +538,7 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
let mut args = launcher.args().to_vec(); let mut args = launcher.args().to_vec();
args.push(text); args.push(text);
match Command::new(launcher.program()).args(&args).spawn() { match start_daemon(launcher.program(), &args) {
Ok(_) => debug!("Launched: {} {:?}", launcher.program(), args), Ok(_) => debug!("Launched: {} {:?}", launcher.program(), args),
Err(_) => warn!("Unable to launch: {} {:?}", launcher.program(), args), Err(_) => warn!("Unable to launch: {} {:?}", launcher.program(), args),
} }

View File

@ -11,25 +11,20 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use std::cmp; #[cfg(not(windows))]
use std::os::unix::process::CommandExt;
#[cfg(not(feature = "nightly"))] use std::process::Command;
#[inline(always)] use std::{cmp, io};
pub unsafe fn unlikely(x: bool) -> bool {
x
}
#[cfg(feature = "nightly")]
pub use ::std::intrinsics::unlikely;
/// Threading utilities /// Threading utilities
pub mod thread { pub mod thread {
/// Like `thread::spawn`, but with a `name` argument /// Like `thread::spawn`, but with a `name` argument
pub fn spawn_named<F, T, S>(name: S, f: F) -> ::std::thread::JoinHandle<T> pub fn spawn_named<F, T, S>(name: S, f: F) -> ::std::thread::JoinHandle<T>
where F: FnOnce() -> T, where
F: FnOnce() -> T,
F: Send + 'static, F: Send + 'static,
T: Send + 'static, T: Send + 'static,
S: Into<String> S: Into<String>,
{ {
::std::thread::Builder::new() ::std::thread::Builder::new()
.name(name.into()) .name(name.into())
@ -37,7 +32,7 @@ pub mod thread {
.expect("thread spawn works") .expect("thread spawn works")
} }
pub use ::std::thread::*; pub use std::thread::*;
} }
pub fn limit<T: Ord>(value: T, min: T, max: T) -> T { pub fn limit<T: Ord>(value: T, min: T, max: T) -> T {
@ -81,6 +76,24 @@ pub mod fmt {
} }
} }
#[cfg(not(windows))]
pub fn start_daemon(program: &str, args: &[String]) -> io::Result<()> {
Command::new(program)
.args(args)
.before_exec(|| unsafe {
::libc::daemon(1, 0);
Ok(())
})
.spawn()?
.wait()
.map(|_| ())
}
#[cfg(windows)]
pub fn start_daemon(program: &str, args: &[String]) -> io::Result<()> {
Command::new(program).args(args).spawn().map(|_| ())
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::limit; use super::limit;