mirror of
https://github.com/astral-sh/uv.git
synced 2025-07-07 13:25:00 +00:00
Use "terminal driver" instead of "shell" in SIGINT docs (#13787)
Some checks are pending
CI / cargo dev generate-all (push) Blocked by required conditions
CI / cargo shear (push) Waiting to run
CI / Determine changes (push) Waiting to run
CI / lint (push) Waiting to run
CI / cargo clippy | ubuntu (push) Blocked by required conditions
CI / cargo clippy | windows (push) Blocked by required conditions
CI / cargo test | ubuntu (push) Blocked by required conditions
CI / cargo test | macos (push) Blocked by required conditions
CI / cargo test | windows (push) Blocked by required conditions
CI / check windows trampoline | aarch64 (push) Blocked by required conditions
CI / check windows trampoline | i686 (push) Blocked by required conditions
CI / check windows trampoline | x86_64 (push) Blocked by required conditions
CI / test windows trampoline | i686 (push) Blocked by required conditions
CI / test windows trampoline | x86_64 (push) Blocked by required conditions
CI / typos (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / build binary | windows aarch64 (push) Blocked by required conditions
CI / build binary | linux libc (push) Blocked by required conditions
CI / build binary | linux musl (push) Blocked by required conditions
CI / build binary | macos aarch64 (push) Blocked by required conditions
CI / build binary | macos x86_64 (push) Blocked by required conditions
CI / build binary | windows x86_64 (push) Blocked by required conditions
CI / cargo build (msrv) (push) Blocked by required conditions
CI / build binary | freebsd (push) Blocked by required conditions
CI / ecosystem test | pydantic/pydantic-core (push) Blocked by required conditions
CI / ecosystem test | prefecthq/prefect (push) Blocked by required conditions
CI / ecosystem test | pallets/flask (push) Blocked by required conditions
CI / smoke test | linux (push) Blocked by required conditions
CI / check system | alpine (push) Blocked by required conditions
CI / smoke test | macos (push) Blocked by required conditions
CI / smoke test | windows x86_64 (push) Blocked by required conditions
CI / smoke test | windows aarch64 (push) Blocked by required conditions
CI / integration test | conda on ubuntu (push) Blocked by required conditions
CI / integration test | deadsnakes python3.9 on ubuntu (push) Blocked by required conditions
CI / integration test | free-threaded on windows (push) Blocked by required conditions
CI / integration test | pypy on ubuntu (push) Blocked by required conditions
CI / integration test | pypy on windows (push) Blocked by required conditions
CI / integration test | graalpy on ubuntu (push) Blocked by required conditions
CI / integration test | graalpy on windows (push) Blocked by required conditions
CI / integration test | pyodide on ubuntu (push) Blocked by required conditions
CI / integration test | github actions (push) Blocked by required conditions
CI / integration test | free-threaded python on github actions (push) Blocked by required conditions
CI / integration test | determine publish changes (push) Blocked by required conditions
CI / integration test | uv publish (push) Blocked by required conditions
CI / integration test | uv_build (push) Blocked by required conditions
CI / check cache | ubuntu (push) Blocked by required conditions
CI / check cache | macos aarch64 (push) Blocked by required conditions
CI / check system | python on debian (push) Blocked by required conditions
CI / check system | python on fedora (push) Blocked by required conditions
CI / check system | python on ubuntu (push) Blocked by required conditions
CI / check system | python on rocky linux 8 (push) Blocked by required conditions
CI / check system | python on rocky linux 9 (push) Blocked by required conditions
CI / check system | graalpy on ubuntu (push) Blocked by required conditions
CI / check system | pypy on ubuntu (push) Blocked by required conditions
CI / check system | pyston (push) Blocked by required conditions
CI / check system | python on macos aarch64 (push) Blocked by required conditions
CI / check system | homebrew python on macos aarch64 (push) Blocked by required conditions
CI / check system | python on macos x86-64 (push) Blocked by required conditions
CI / check system | python3.10 on windows x86-64 (push) Blocked by required conditions
CI / check system | python3.10 on windows x86 (push) Blocked by required conditions
CI / check system | python3.13 on windows x86-64 (push) Blocked by required conditions
CI / check system | x86-64 python3.13 on windows aarch64 (push) Blocked by required conditions
CI / check system | windows registry (push) Blocked by required conditions
CI / check system | python3.12 via chocolatey (push) Blocked by required conditions
CI / check system | python3.9 via pyenv (push) Blocked by required conditions
CI / check system | python3.13 (push) Blocked by required conditions
CI / check system | conda3.11 on macos aarch64 (push) Blocked by required conditions
CI / check system | conda3.8 on macos aarch64 (push) Blocked by required conditions
CI / check system | conda3.11 on linux x86-64 (push) Blocked by required conditions
CI / check system | conda3.8 on linux x86-64 (push) Blocked by required conditions
CI / check system | conda3.11 on windows x86-64 (push) Blocked by required conditions
CI / check system | conda3.8 on windows x86-64 (push) Blocked by required conditions
CI / check system | amazonlinux (push) Blocked by required conditions
CI / check system | embedded python3.10 on windows x86-64 (push) Blocked by required conditions
CI / benchmarks | walltime aarch64 linux (push) Blocked by required conditions
CI / benchmarks | instrumented (push) Blocked by required conditions
Some checks are pending
CI / cargo dev generate-all (push) Blocked by required conditions
CI / cargo shear (push) Waiting to run
CI / Determine changes (push) Waiting to run
CI / lint (push) Waiting to run
CI / cargo clippy | ubuntu (push) Blocked by required conditions
CI / cargo clippy | windows (push) Blocked by required conditions
CI / cargo test | ubuntu (push) Blocked by required conditions
CI / cargo test | macos (push) Blocked by required conditions
CI / cargo test | windows (push) Blocked by required conditions
CI / check windows trampoline | aarch64 (push) Blocked by required conditions
CI / check windows trampoline | i686 (push) Blocked by required conditions
CI / check windows trampoline | x86_64 (push) Blocked by required conditions
CI / test windows trampoline | i686 (push) Blocked by required conditions
CI / test windows trampoline | x86_64 (push) Blocked by required conditions
CI / typos (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / build binary | windows aarch64 (push) Blocked by required conditions
CI / build binary | linux libc (push) Blocked by required conditions
CI / build binary | linux musl (push) Blocked by required conditions
CI / build binary | macos aarch64 (push) Blocked by required conditions
CI / build binary | macos x86_64 (push) Blocked by required conditions
CI / build binary | windows x86_64 (push) Blocked by required conditions
CI / cargo build (msrv) (push) Blocked by required conditions
CI / build binary | freebsd (push) Blocked by required conditions
CI / ecosystem test | pydantic/pydantic-core (push) Blocked by required conditions
CI / ecosystem test | prefecthq/prefect (push) Blocked by required conditions
CI / ecosystem test | pallets/flask (push) Blocked by required conditions
CI / smoke test | linux (push) Blocked by required conditions
CI / check system | alpine (push) Blocked by required conditions
CI / smoke test | macos (push) Blocked by required conditions
CI / smoke test | windows x86_64 (push) Blocked by required conditions
CI / smoke test | windows aarch64 (push) Blocked by required conditions
CI / integration test | conda on ubuntu (push) Blocked by required conditions
CI / integration test | deadsnakes python3.9 on ubuntu (push) Blocked by required conditions
CI / integration test | free-threaded on windows (push) Blocked by required conditions
CI / integration test | pypy on ubuntu (push) Blocked by required conditions
CI / integration test | pypy on windows (push) Blocked by required conditions
CI / integration test | graalpy on ubuntu (push) Blocked by required conditions
CI / integration test | graalpy on windows (push) Blocked by required conditions
CI / integration test | pyodide on ubuntu (push) Blocked by required conditions
CI / integration test | github actions (push) Blocked by required conditions
CI / integration test | free-threaded python on github actions (push) Blocked by required conditions
CI / integration test | determine publish changes (push) Blocked by required conditions
CI / integration test | uv publish (push) Blocked by required conditions
CI / integration test | uv_build (push) Blocked by required conditions
CI / check cache | ubuntu (push) Blocked by required conditions
CI / check cache | macos aarch64 (push) Blocked by required conditions
CI / check system | python on debian (push) Blocked by required conditions
CI / check system | python on fedora (push) Blocked by required conditions
CI / check system | python on ubuntu (push) Blocked by required conditions
CI / check system | python on rocky linux 8 (push) Blocked by required conditions
CI / check system | python on rocky linux 9 (push) Blocked by required conditions
CI / check system | graalpy on ubuntu (push) Blocked by required conditions
CI / check system | pypy on ubuntu (push) Blocked by required conditions
CI / check system | pyston (push) Blocked by required conditions
CI / check system | python on macos aarch64 (push) Blocked by required conditions
CI / check system | homebrew python on macos aarch64 (push) Blocked by required conditions
CI / check system | python on macos x86-64 (push) Blocked by required conditions
CI / check system | python3.10 on windows x86-64 (push) Blocked by required conditions
CI / check system | python3.10 on windows x86 (push) Blocked by required conditions
CI / check system | python3.13 on windows x86-64 (push) Blocked by required conditions
CI / check system | x86-64 python3.13 on windows aarch64 (push) Blocked by required conditions
CI / check system | windows registry (push) Blocked by required conditions
CI / check system | python3.12 via chocolatey (push) Blocked by required conditions
CI / check system | python3.9 via pyenv (push) Blocked by required conditions
CI / check system | python3.13 (push) Blocked by required conditions
CI / check system | conda3.11 on macos aarch64 (push) Blocked by required conditions
CI / check system | conda3.8 on macos aarch64 (push) Blocked by required conditions
CI / check system | conda3.11 on linux x86-64 (push) Blocked by required conditions
CI / check system | conda3.8 on linux x86-64 (push) Blocked by required conditions
CI / check system | conda3.11 on windows x86-64 (push) Blocked by required conditions
CI / check system | conda3.8 on windows x86-64 (push) Blocked by required conditions
CI / check system | amazonlinux (push) Blocked by required conditions
CI / check system | embedded python3.10 on windows x86-64 (push) Blocked by required conditions
CI / benchmarks | walltime aarch64 linux (push) Blocked by required conditions
CI / benchmarks | instrumented (push) Blocked by required conditions
Addressing the comment at https://github.com/astral-sh/uv/issues/12108#issuecomment-2925703719
This commit is contained in:
parent
f5c3601445
commit
3ca8d074a4
2 changed files with 29 additions and 29 deletions
|
@ -9,33 +9,33 @@ use crate::commands::ExitStatus;
|
|||
/// long as the command is the last thing that runs in this process; otherwise, we'd need to restore
|
||||
/// the default signal handlers after the command completes.
|
||||
pub(crate) async fn run_to_completion(mut handle: Child) -> anyhow::Result<ExitStatus> {
|
||||
// On Unix, shells will send SIGINT to the active process group when a user presses `Ctrl-C`. In
|
||||
// general, this means that uv should ignore SIGINT, allowing the child process to cleanly exit
|
||||
// instead. If uv forwarded the SIGINT immediately, the child process would receive _two_ SIGINT
|
||||
// signals which has semantic meaning for some programs, i.e., slow exit on the first signal and
|
||||
// fast exit on the second. The exception to this is if a child process changes its process
|
||||
// group, in which case the shell will _not_ send SIGINT to the child process and uv must take
|
||||
// ownership of forwarding the signal.
|
||||
// On Unix, the terminal driver will send SIGINT to the active process group when a user presses
|
||||
// `Ctrl-C`. In general, this means that uv should ignore SIGINT, allowing the child process to
|
||||
// cleanly exit instead. If uv forwarded the SIGINT immediately, the child process would receive
|
||||
// _two_ SIGINT signals which has semantic meaning for some programs, i.e., slow exit on the
|
||||
// first signal and fast exit on the second. The exception to this is if a child process changes
|
||||
// its process group, in which case the terminal driver will _not_ send SIGINT to the child
|
||||
// process and uv must take ownership of forwarding the signal.
|
||||
//
|
||||
// Note this assumes an interactive shell. If a signal is sent directly to the uv parent process
|
||||
// (e.g., `kill -2 <pid>`), the process group is not involved and a signal is not sent to the
|
||||
// child by default. In this context, uv must forward the signal to the child. We work around
|
||||
// this by forwarding SIGINT if it is received more than once. We could attempt to infer if the
|
||||
// parent is a shell using TTY detection(?), but there hasn't been sufficient motivation to
|
||||
// explore alternatives yet.
|
||||
// Note this assumes an interactive terminal. If a signal is sent directly to the uv parent
|
||||
// process (e.g., `kill -2 <pid>`), the process group is not involved and a signal is not sent
|
||||
// to the child by default. In this context, uv must forward the signal to the child. We work
|
||||
// around this by forwarding SIGINT if it is received more than once. We could attempt to infer
|
||||
// if the parent is a terminal using TTY detection(?), but there hasn't been sufficient
|
||||
// motivation to explore alternatives yet.
|
||||
//
|
||||
// Use of SIGTERM is also a bit complicated. If a shell receives a SIGTERM, it just waits for
|
||||
// Use of SIGTERM is also a bit complicated. If a terminal receives a SIGTERM, it just waits for
|
||||
// its children to exit — multiple SIGTERMs do not have any effect and the signals are not
|
||||
// forwarded to the children. Consequently, the description for SIGINT above does not apply to
|
||||
// SIGTERM in shells. It is _possible_ to have a parent process that sends a SIGTERM to the
|
||||
// process group; for example, `tini` supports this via a `-g` option. In this case, it's
|
||||
// possible that uv will improperly send a second SIGTERM to the child process. However,
|
||||
// this seems preferable to not forwarding it in the first place. In the Docker case, if `uv`
|
||||
// is invoked directly (instead of via an init system), it's PID 1 which has a special-cased
|
||||
// default signal handler for SIGTERM by default. Generally, if a process receives a SIGTERM and
|
||||
// does not have a SIGTERM handler, it is terminated. However, if PID 1 receives a SIGTERM, it
|
||||
// is not terminated. In this context, it is essential for uv to forward the SIGTERM to the
|
||||
// child process or the process will not be killable.
|
||||
// SIGTERM in the terminal driver. It is _possible_ to have a parent process that sends a
|
||||
// SIGTERM to the process group; for example, `tini` supports this via a `-g` option. In this
|
||||
// case, it's possible that uv will improperly send a second SIGTERM to the child process.
|
||||
// However, this seems preferable to not forwarding it in the first place. In the Docker case,
|
||||
// if `uv` is invoked directly (instead of via an init system), it's PID 1 which has a
|
||||
// special-cased default signal handler for SIGTERM by default. Generally, if a process receives
|
||||
// a SIGTERM and does not have a SIGTERM handler, it is terminated. However, if PID 1 receives a
|
||||
// SIGTERM, it is not terminated. In this context, it is essential for uv to forward the SIGTERM
|
||||
// to the child process or the process will not be killable.
|
||||
#[cfg(unix)]
|
||||
let status = {
|
||||
use std::ops::Deref;
|
||||
|
@ -162,8 +162,8 @@ pub(crate) async fn run_to_completion(mut handle: Child) -> anyhow::Result<ExitS
|
|||
continue;
|
||||
}
|
||||
|
||||
// The shell may still be forwarding these signals, give the child a moment to
|
||||
// handle that signal before hitting it with another one
|
||||
// The terminal may still be forwarding these signals, give the child a moment
|
||||
// to handle that signal before hitting it with another one
|
||||
debug!("Received SIGINT, forwarding to child at {child_pid} in 200ms");
|
||||
tokio::time::sleep(std::time::Duration::from_millis(200)).await;
|
||||
let _ = signal::kill(child_pid, signal::Signal::SIGINT);
|
||||
|
@ -176,7 +176,7 @@ pub(crate) async fn run_to_completion(mut handle: Child) -> anyhow::Result<ExitS
|
|||
};
|
||||
|
||||
// We unconditionally forward SIGTERM to the child process; unlike SIGINT, this
|
||||
// isn't usually handled by the shell and in cases like
|
||||
// isn't usually handled by the terminal.
|
||||
debug!("Received SIGTERM, forwarding to child at {child_pid}");
|
||||
let _ = signal::kill(child_pid, signal::Signal::SIGTERM);
|
||||
}
|
||||
|
|
|
@ -91,9 +91,9 @@ uv does not cede control of the process to the spawned command in order to provi
|
|||
messages on failure. Consequently, uv is responsible for forwarding some signals to the child
|
||||
process the requested command runs in.
|
||||
|
||||
On Unix systems, uv will forward SIGINT and SIGTERM to the child process. Since shells send SIGINT
|
||||
to the foreground process group on Ctrl-C, uv will only forward a SIGINT to the child process if it
|
||||
is seen more than once or the child process group differs from uv's.
|
||||
On Unix systems, uv will forward SIGINT and SIGTERM to the child process. Since terminals send
|
||||
SIGINT to the foreground process group on Ctrl-C, uv will only forward a SIGINT to the child process
|
||||
if it is sent more than once or the child process group differs from uv's.
|
||||
|
||||
On Windows, these concepts do not apply and uv ignores Ctrl-C events, deferring handling to the
|
||||
child process so it can exit cleanly.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue