From e015956de721ef8e67f4d069ee46c28ef71f5744 Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Fri, 28 Feb 2025 03:58:51 +0100 Subject: [PATCH] Orphan background tasks to work around terminals being sensitive to unreaped processes When a command like "long-running-command &" exits, the resulting SIGCHLD is queued in the topic monitor. We do not process this signal immediately but only after e.g. the next command has finished. Only then do we reap the child process. Some terminals, such as Terminal.app, refuse to close when there are unreaped processes associated with the terminal -- as in, having the same session ID, see setsid(3). In future, we might want to reap proactively. For now, apply an isolated workaround: instead of taking care of a child process, double-fork to create an orphaned process. Since the orphan will be reaped by PID 1, we can eventually close Terminal.app without it asking for confirmation. /bin/sh -c '( "$@" ) >/dev/null 2>&1 &' -- cmd arg1 arg2 This fix confines the problem to the period during which a background process is running. To complete the fix, we would need to call setsid to detach the background process from a controlling terminal. That seems to be desirable however macOS does provide a setsid utility. setsid cmd arg1 arg2 >/dev/null 2>&1 Fixes #11181 --- share/functions/__fish_apropos.fish | 3 +-- share/functions/__fish_config_interactive.fish | 5 ++--- share/functions/fish_git_prompt.fish | 3 +-- share/functions/help.fish | 3 +-- 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/share/functions/__fish_apropos.fish b/share/functions/__fish_apropos.fish index 8bf412e98..6c4d70be5 100644 --- a/share/functions/__fish_apropos.fish +++ b/share/functions/__fish_apropos.fish @@ -40,8 +40,7 @@ if test $status -eq 0 -a (count $sysver) -eq 3 if test $age -ge $max_age test -d "$dir" || mkdir -m 700 -p $dir - /usr/libexec/makewhatis -o "$whatis" (/usr/bin/manpath | string split : | xargs realpath) >/dev/null 2>&1 /dev/null 2>&1 $__fish_config_dir/config.fish set -l update_args -B $__fish_data_dir/tools/create_manpage_completions.py --manpath --cleanup-in $__fish_user_data_dir/generated_completions --cleanup-in $__fish_cache_dir/generated_completions if set -l python (__fish_anypython) # Run python directly in the background and swallow all output - $python $update_args >/dev/null 2>&1 & - # Then disown the job so that it continues to run in case of an early exit (#6269) - disown >/dev/null 2>&1 + # Orphan the job so that it continues to run in case of an early exit (#6269) + /bin/sh -c '( "$@" ) >/dev/null 2>&1 &' -- $python $update_args end end end diff --git a/share/functions/fish_git_prompt.fish b/share/functions/fish_git_prompt.fish index d9b7281ec..7127ee865 100644 --- a/share/functions/fish_git_prompt.fish +++ b/share/functions/fish_git_prompt.fish @@ -180,8 +180,7 @@ if string match -q Darwin -- (uname) && string match -q /usr/bin/git -- (command else # git is installed, but on the first run it may be very slow as xcrun needs to populate the cache. # Kick it off in the background to populate the cache. - /bin/sh -c '/usr/bin/git --version; touch /tmp/__fish_git_ready' &>/dev/null & - disown $last_pid &>/dev/null + /bin/sh -c '( /usr/bin/git --version; touch /tmp/__fish_git_ready ) >/dev/null 2>&1 &' function __fish_git_prompt_ready path is /tmp/__fish_git_ready || return 1 # git is ready, erase the function. diff --git a/share/functions/help.fish b/share/functions/help.fish index 7a1b06f43..27a8aa350 100644 --- a/share/functions/help.fish +++ b/share/functions/help.fish @@ -250,8 +250,7 @@ function help --description 'Show help for the fish shell' # The space before the /c is to prevent msys2 from expanding it to a path $fish_browser " /c" start $page_url else if contains -- $fish_browser[1] $graphical_browsers - $fish_browser $page_url & - disown $last_pid >/dev/null 2>&1 + /bin/sh -c '( "$@" ) &' -- $fish_browser $page_url else $fish_browser $page_url end