mirror of
https://github.com/astral-sh/uv.git
synced 2025-07-07 21:35: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
|
/// 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.
|
/// the default signal handlers after the command completes.
|
||||||
pub(crate) async fn run_to_completion(mut handle: Child) -> anyhow::Result<ExitStatus> {
|
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
|
// On Unix, the terminal driver will send SIGINT to the active process group when a user presses
|
||||||
// general, this means that uv should ignore SIGINT, allowing the child process to cleanly exit
|
// `Ctrl-C`. In general, this means that uv should ignore SIGINT, allowing the child process to
|
||||||
// instead. If uv forwarded the SIGINT immediately, the child process would receive _two_ SIGINT
|
// cleanly exit instead. If uv forwarded the SIGINT immediately, the child process would receive
|
||||||
// signals which has semantic meaning for some programs, i.e., slow exit on the first signal and
|
// _two_ SIGINT signals which has semantic meaning for some programs, i.e., slow exit on the
|
||||||
// fast exit on the second. The exception to this is if a child process changes its process
|
// first signal and fast exit on the second. The exception to this is if a child process changes
|
||||||
// group, in which case the shell will _not_ send SIGINT to the child process and uv must take
|
// its process group, in which case the terminal driver will _not_ send SIGINT to the child
|
||||||
// ownership of forwarding the signal.
|
// 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
|
// Note this assumes an interactive terminal. If a signal is sent directly to the uv parent
|
||||||
// (e.g., `kill -2 <pid>`), the process group is not involved and a signal is not sent to the
|
// process (e.g., `kill -2 <pid>`), the process group is not involved and a signal is not sent
|
||||||
// child by default. In this context, uv must forward the signal to the child. We work around
|
// to the child by default. In this context, uv must forward the signal to the child. We work
|
||||||
// this by forwarding SIGINT if it is received more than once. We could attempt to infer if the
|
// around this by forwarding SIGINT if it is received more than once. We could attempt to infer
|
||||||
// parent is a shell using TTY detection(?), but there hasn't been sufficient motivation to
|
// if the parent is a terminal using TTY detection(?), but there hasn't been sufficient
|
||||||
// explore alternatives yet.
|
// 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
|
// 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
|
// 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
|
// SIGTERM in the terminal driver. It is _possible_ to have a parent process that sends a
|
||||||
// process group; for example, `tini` supports this via a `-g` option. In this case, it's
|
// SIGTERM to the process group; for example, `tini` supports this via a `-g` option. In this
|
||||||
// possible that uv will improperly send a second SIGTERM to the child process. However,
|
// case, it's possible that uv will improperly send a second SIGTERM to the child process.
|
||||||
// this seems preferable to not forwarding it in the first place. In the Docker case, if `uv`
|
// However, this seems preferable to not forwarding it in the first place. In the Docker case,
|
||||||
// is invoked directly (instead of via an init system), it's PID 1 which has a special-cased
|
// if `uv` is invoked directly (instead of via an init system), it's PID 1 which has a
|
||||||
// default signal handler for SIGTERM by default. Generally, if a process receives a SIGTERM and
|
// special-cased default signal handler for SIGTERM by default. Generally, if a process receives
|
||||||
// does not have a SIGTERM handler, it is terminated. However, if PID 1 receives a SIGTERM, it
|
// a SIGTERM and does not have a SIGTERM handler, it is terminated. However, if PID 1 receives a
|
||||||
// is not terminated. In this context, it is essential for uv to forward the SIGTERM to the
|
// SIGTERM, it is not terminated. In this context, it is essential for uv to forward the SIGTERM
|
||||||
// child process or the process will not be killable.
|
// to the child process or the process will not be killable.
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
let status = {
|
let status = {
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
@ -162,8 +162,8 @@ pub(crate) async fn run_to_completion(mut handle: Child) -> anyhow::Result<ExitS
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The shell may still be forwarding these signals, give the child a moment to
|
// The terminal may still be forwarding these signals, give the child a moment
|
||||||
// handle that signal before hitting it with another one
|
// to handle that signal before hitting it with another one
|
||||||
debug!("Received SIGINT, forwarding to child at {child_pid} in 200ms");
|
debug!("Received SIGINT, forwarding to child at {child_pid} in 200ms");
|
||||||
tokio::time::sleep(std::time::Duration::from_millis(200)).await;
|
tokio::time::sleep(std::time::Duration::from_millis(200)).await;
|
||||||
let _ = signal::kill(child_pid, signal::Signal::SIGINT);
|
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
|
// 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}");
|
debug!("Received SIGTERM, forwarding to child at {child_pid}");
|
||||||
let _ = signal::kill(child_pid, signal::Signal::SIGTERM);
|
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
|
messages on failure. Consequently, uv is responsible for forwarding some signals to the child
|
||||||
process the requested command runs in.
|
process the requested command runs in.
|
||||||
|
|
||||||
On Unix systems, uv will forward SIGINT and SIGTERM to the child process. Since shells send SIGINT
|
On Unix systems, uv will forward SIGINT and SIGTERM to the child process. Since terminals send
|
||||||
to the foreground process group on Ctrl-C, uv will only forward a SIGINT to the child process if it
|
SIGINT to the foreground process group on Ctrl-C, uv will only forward a SIGINT to the child process
|
||||||
is seen more than once or the child process group differs from uv's.
|
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
|
On Windows, these concepts do not apply and uv ignores Ctrl-C events, deferring handling to the
|
||||||
child process so it can exit cleanly.
|
child process so it can exit cleanly.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue