nix: use killpg

Part of #12380
This commit is contained in:
Daniel Rainer
2026-01-25 21:28:58 +01:00
committed by Johannes Altmanninger
parent ac1c77d499
commit 74b03de449
3 changed files with 50 additions and 59 deletions

View File

@@ -6,7 +6,7 @@
use crate::proc::{Job, add_disowned_job};
use crate::{builtins::shared::HelpOnlyCmdOpts, localization::wgettext_fmt};
use fish_widestring::wstr;
use libc::SIGCONT;
use nix::sys::signal::{Signal, killpg};
/// Helper for builtin_disown.
fn disown_job(cmd: &wstr, streams: &mut IoStreams, j: &Job) {
@@ -19,9 +19,7 @@ fn disown_job(cmd: &wstr, streams: &mut IoStreams, j: &Job) {
let pgid = j.get_pgid();
if j.is_stopped() {
if let Some(pgid) = pgid {
unsafe {
libc::killpg(pgid.as_pid_t(), SIGCONT);
}
let _ = killpg(pgid.as_nix_pid(), Some(Signal::SIGCONT));
}
streams.err.append(&wgettext_fmt!(
"%s: job %d ('%s') was stopped and has been signalled to continue.\n",

View File

@@ -3,9 +3,7 @@
//! the exec library will call proc to create representations of the running jobs as needed.
use crate::ast;
use crate::common::{
Timepoint, WSL, charptr2wcstring, escape, is_windows_subsystem_for_linux, timef,
};
use crate::common::{Timepoint, WSL, escape, is_windows_subsystem_for_linux, timef};
use crate::env::Statuses;
use crate::event::{self, Event};
use crate::flog::{flog, flogf};
@@ -25,13 +23,13 @@
use cfg_if::cfg_if;
use fish_widestring::ToWString;
use libc::{
_SC_CLK_TCK, EXIT_SUCCESS, SIG_IGN, SIGABRT, SIGBUS, SIGCONT, SIGFPE, SIGHUP, SIGILL, SIGINT,
SIGKILL, SIGPIPE, SIGQUIT, SIGSEGV, SIGSYS, SIGTTOU, STDOUT_FILENO, WCONTINUED, WEXITSTATUS,
WIFCONTINUED, WIFEXITED, WIFSIGNALED, WIFSTOPPED, WNOHANG, WTERMSIG, WUNTRACED,
_SC_CLK_TCK, EXIT_SUCCESS, SIG_IGN, SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGINT, SIGPIPE, SIGQUIT,
SIGSEGV, SIGSYS, SIGTTOU, STDOUT_FILENO, WCONTINUED, WEXITSTATUS, WIFCONTINUED, WIFEXITED,
WIFSIGNALED, WIFSTOPPED, WNOHANG, WTERMSIG, WUNTRACED,
};
use nix::{
sys::{
signal::{SaFlags, SigAction, SigHandler, SigSet},
signal::{SaFlags, SigAction, SigHandler, SigSet, Signal as NixSignal, kill, killpg},
wait::{WaitPidFlag, WaitStatus, waitpid},
},
unistd::getpgrp,
@@ -835,7 +833,7 @@ pub fn continue_job(&self, parser: &Parser, block_io: Option<&IoChain>) {
/// Return true on success, false if we failed to send the signal.
pub fn resume(&self) -> bool {
self.mut_flags().notified_of_stop = false;
if !self.signal(SIGCONT) {
if !self.signal(NixSignal::SIGCONT) {
flogf!(
proc_pgroup,
"Failed to send SIGCONT to procs in job %s",
@@ -853,24 +851,17 @@ pub fn resume(&self) -> bool {
/// Send the specified signal to all processes in this job.
/// Return true on success, false on failure.
pub fn signal(&self, signal: i32) -> bool {
pub fn signal(&self, signal: NixSignal) -> bool {
if let Some(pgid) = self.group().get_pgid() {
if unsafe { libc::killpg(pgid.as_pid_t(), signal) } == -1 {
let strsignal = unsafe { libc::strsignal(signal) };
let strsignal = if strsignal.is_null() {
L!("(nil)").to_owned()
} else {
charptr2wcstring(strsignal)
};
if killpg(pgid.as_nix_pid(), signal).is_err() {
let strsignal = signal.as_str();
wperror(&sprintf!("killpg(%d, %s)", pgid, strsignal));
return false;
}
} else {
// This job lives in fish's pgroup and we need to signal procs individually.
for p in self.external_procs() {
if !p.is_completed()
&& unsafe { libc::kill(p.pid().unwrap().as_pid_t(), signal) } == -1
{
if !p.is_completed() && kill(p.pid().unwrap().as_nix_pid(), signal).is_err() {
return false;
}
}
@@ -1123,9 +1114,9 @@ pub fn hup_jobs(jobs: &JobList) {
for j in jobs {
let Some(pgid) = j.get_pgid() else { continue };
if pgid.as_nix_pid() != fish_pgrp && !j.is_completed() {
j.signal(SIGHUP);
j.signal(NixSignal::SIGHUP);
if j.is_stopped() {
j.signal(SIGCONT);
j.signal(NixSignal::SIGCONT);
}
// For most applications, the above alone is sufficient for the suspended process to
@@ -1149,7 +1140,7 @@ pub fn hup_jobs(jobs: &JobList) {
// handle SIGHUP+SIGCONT without running into SIGTTOU.
std::thread::sleep(std::time::Duration::from_millis(50));
for j in kill_list.drain(..) {
j.signal(SIGKILL);
j.signal(NixSignal::SIGKILL);
}
}
}

View File

@@ -17,37 +17,6 @@
//! control-C from generating SIGINT, so failing to disable these would prevent cancellation of wildcard
//! expansion, etc.
use crate::portable_atomic::AtomicU64;
use fish_common::{UTF8_BOM_WCHAR, help_section};
use fish_fallback::lowercase;
use fish_wcstringutil::{IsPrefix, is_prefix};
use libc::{
_POSIX_VDISABLE, ECHO, EINTR, EIO, EISDIR, ENOTTY, EPERM, ESRCH, FLUSHO, ICANON, ICRNL, IEXTEN,
INLCR, IXOFF, IXON, O_NONBLOCK, O_RDONLY, ONLCR, OPOST, SIGINT, SIGTTIN, STDERR_FILENO,
STDIN_FILENO, STDOUT_FILENO, TCSANOW, VMIN, VQUIT, VSUSP, VTIME, c_char,
};
use nix::fcntl::OFlag;
use nix::sys::stat::Mode;
use nix::unistd::getpgrp;
use std::borrow::Cow;
use std::cell::UnsafeCell;
use std::cmp;
use std::io::BufReader;
use std::mem::MaybeUninit;
use std::num::NonZeroUsize;
use std::ops::ControlFlow;
use std::ops::Range;
use std::os::fd::BorrowedFd;
use std::os::fd::FromRawFd;
use std::os::fd::OwnedFd;
use std::os::fd::{AsRawFd, RawFd};
use std::pin::Pin;
use std::sync::atomic::{AtomicI32, AtomicU8, AtomicU32, Ordering};
use std::sync::{Arc, LazyLock, Mutex, MutexGuard, OnceLock};
use std::time::{Duration, Instant};
use errno::{Errno, errno};
use super::history_search::{ReaderHistorySearch, SearchMode, smartcase_flags};
use super::iothreads::{self, Debouncers};
use super::word_motion::{MoveWordDir, MoveWordStateMachine, MoveWordStyle};
@@ -112,6 +81,7 @@
get_token_extent, lineno, locate_cmdsubst_range,
};
use crate::parser::{BlockType, EvalRes, Parser, ParserEnvSetMode};
use crate::portable_atomic::AtomicU64;
use crate::prelude::*;
use crate::proc::{
HAVE_PROC_STAT, hup_jobs, is_interactive_session, job_reap, jobs_requiring_warning_on_exit,
@@ -146,12 +116,45 @@
use crate::wutil::{fstat, perror, write_to_fd, wstat};
use crate::{abbrs, event, function};
use assert_matches::assert_matches;
use errno::{Errno, errno};
use fish_common::{UTF8_BOM_WCHAR, help_section};
use fish_fallback::fish_wcwidth;
use fish_fallback::lowercase;
use fish_wcstringutil::{
CaseSensitivity, StringFuzzyMatch, count_preceding_backslashes, join_strings,
string_prefixes_string, string_prefixes_string_case_insensitive,
string_prefixes_string_maybe_case_insensitive,
};
use fish_wcstringutil::{IsPrefix, is_prefix};
use libc::{
_POSIX_VDISABLE, ECHO, EINTR, EIO, EISDIR, ENOTTY, EPERM, ESRCH, FLUSHO, ICANON, ICRNL, IEXTEN,
INLCR, IXOFF, IXON, O_NONBLOCK, O_RDONLY, ONLCR, OPOST, SIGINT, STDERR_FILENO, STDIN_FILENO,
STDOUT_FILENO, TCSANOW, VMIN, VQUIT, VSUSP, VTIME, c_char,
};
use nix::{
fcntl::OFlag,
sys::{
signal::{Signal, killpg},
stat::Mode,
},
unistd::getpgrp,
};
use std::{
borrow::Cow,
cell::UnsafeCell,
cmp,
io::BufReader,
mem::MaybeUninit,
num::NonZeroUsize,
ops::{ControlFlow, Range},
os::fd::{AsRawFd, BorrowedFd, FromRawFd, OwnedFd, RawFd},
pin::Pin,
sync::{
Arc, LazyLock, Mutex, MutexGuard, OnceLock,
atomic::{AtomicI32, AtomicU8, AtomicU32, Ordering},
},
time::{Duration, Instant},
};
/// A description of where fish is in the process of exiting.
#[repr(u8)]
@@ -4921,8 +4924,7 @@ fn acquire_tty_or_exit(shell_pgid: libc::pid_t) {
}
// Try stopping us.
let ret = unsafe { libc::killpg(shell_pgid, SIGTTIN) };
if ret < 0 {
if killpg(nix::unistd::Pid::from_raw(shell_pgid), Signal::SIGTTIN).is_err() {
perror("killpg(shell_pgid, SIGTTIN)");
exit_without_destructors(1);
}