mirror of https://github.com/astral-sh/uv
Always spawn a main2 thread to normalize main stack size issues (#10479)
Also removes UV_STACK_SIZE and uses RUST_MIN_STACK instead, tweaking docs to reflect the differences. Fixes #10367
This commit is contained in:
parent
a7fe84aa03
commit
80ac8db7db
|
|
@ -305,9 +305,6 @@ jobs:
|
||||||
|
|
||||||
- name: "Smoke test"
|
- name: "Smoke test"
|
||||||
working-directory: ${{ env.UV_WORKSPACE }}
|
working-directory: ${{ env.UV_WORKSPACE }}
|
||||||
env:
|
|
||||||
# Avoid debug build stack overflows.
|
|
||||||
UV_STACK_SIZE: 3000000 # 3 megabyte, triple the default on windows
|
|
||||||
run: |
|
run: |
|
||||||
Set-Alias -Name uv -Value ./target/debug/uv
|
Set-Alias -Name uv -Value ./target/debug/uv
|
||||||
uv venv -v
|
uv venv -v
|
||||||
|
|
@ -316,9 +313,6 @@ jobs:
|
||||||
- name: "Smoke test completion"
|
- name: "Smoke test completion"
|
||||||
working-directory: ${{ env.UV_WORKSPACE }}
|
working-directory: ${{ env.UV_WORKSPACE }}
|
||||||
shell: powershell
|
shell: powershell
|
||||||
env:
|
|
||||||
# Avoid debug build stack overflows.
|
|
||||||
UV_STACK_SIZE: 3000000 # 3 megabyte, triple the default on windows
|
|
||||||
run: |
|
run: |
|
||||||
Set-Alias -Name uv -Value ./target/debug/uv
|
Set-Alias -Name uv -Value ./target/debug/uv
|
||||||
Set-Alias -Name uvx -Value ./target/debug/uvx
|
Set-Alias -Name uvx -Value ./target/debug/uvx
|
||||||
|
|
@ -744,9 +738,6 @@ jobs:
|
||||||
needs: build-binary-windows
|
needs: build-binary-windows
|
||||||
name: "integration test | free-threaded on windows"
|
name: "integration test | free-threaded on windows"
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
env:
|
|
||||||
# Avoid debug build stack overflows.
|
|
||||||
UV_STACK_SIZE: 3000000 # 3 megabyte, triple the default on windows
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: "Download binary"
|
- name: "Download binary"
|
||||||
|
|
@ -908,9 +899,6 @@ jobs:
|
||||||
& .venv\Scripts\python.exe --version
|
& .venv\Scripts\python.exe --version
|
||||||
|
|
||||||
- name: "Check install"
|
- name: "Check install"
|
||||||
env:
|
|
||||||
# Avoid debug build stack overflows.
|
|
||||||
UV_STACK_SIZE: 3000000 # 3 megabyte, triple the default on windows
|
|
||||||
run: |
|
run: |
|
||||||
.\uv.exe pip install anyio
|
.\uv.exe pip install anyio
|
||||||
|
|
||||||
|
|
@ -1040,9 +1028,6 @@ jobs:
|
||||||
& .venv\Scripts\python.exe --version
|
& .venv\Scripts\python.exe --version
|
||||||
|
|
||||||
- name: "Check install"
|
- name: "Check install"
|
||||||
env:
|
|
||||||
# Avoid debug build stack overflows.
|
|
||||||
UV_STACK_SIZE: 3000000 # 3 megabyte, triple the default on windows
|
|
||||||
run: |
|
run: |
|
||||||
.\uv.exe pip install anyio
|
.\uv.exe pip install anyio
|
||||||
|
|
||||||
|
|
@ -1534,9 +1519,6 @@ jobs:
|
||||||
needs: build-binary-windows
|
needs: build-binary-windows
|
||||||
name: "check system | python3.10 on windows"
|
name: "check system | python3.10 on windows"
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
env:
|
|
||||||
# Avoid debug build stack overflows.
|
|
||||||
UV_STACK_SIZE: 3000000 # 3 megabyte, triple the default on windows
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
|
@ -1560,9 +1542,6 @@ jobs:
|
||||||
needs: build-binary-windows
|
needs: build-binary-windows
|
||||||
name: "check system | python3.10 on windows x86"
|
name: "check system | python3.10 on windows x86"
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
env:
|
|
||||||
# Avoid debug build stack overflows.
|
|
||||||
UV_STACK_SIZE: 3000000 # 3 megabyte, triple the default on windows
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
|
@ -1587,9 +1566,6 @@ jobs:
|
||||||
needs: build-binary-windows
|
needs: build-binary-windows
|
||||||
name: "check system | python3.13 on windows"
|
name: "check system | python3.13 on windows"
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
env:
|
|
||||||
# Avoid debug build stack overflows.
|
|
||||||
UV_STACK_SIZE: 3000000 # 3 megabyte, triple the default on windows
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
|
@ -1615,9 +1591,6 @@ jobs:
|
||||||
needs: build-binary-windows
|
needs: build-binary-windows
|
||||||
name: "check system | python3.12 via chocolatey"
|
name: "check system | python3.12 via chocolatey"
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
env:
|
|
||||||
# Avoid debug build stack overflows.
|
|
||||||
UV_STACK_SIZE: 3000000 # 3 megabyte, triple the default on windows
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
|
@ -1750,9 +1723,6 @@ jobs:
|
||||||
|
|
||||||
- name: "Validate global Python install"
|
- name: "Validate global Python install"
|
||||||
shell: bash -el {0}
|
shell: bash -el {0}
|
||||||
env:
|
|
||||||
# Avoid debug build stack overflows.
|
|
||||||
UV_STACK_SIZE: 3000000 # 3 megabyte, triple the default on windows
|
|
||||||
run: python ./scripts/check_system_python.py --uv ./uv
|
run: python ./scripts/check_system_python.py --uv ./uv
|
||||||
|
|
||||||
system-test-amazonlinux:
|
system-test-amazonlinux:
|
||||||
|
|
@ -1789,9 +1759,6 @@ jobs:
|
||||||
needs: build-binary-windows
|
needs: build-binary-windows
|
||||||
name: "check system | embedded python3.10 on windows"
|
name: "check system | embedded python3.10 on windows"
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
env:
|
|
||||||
# Avoid debug build stack overflows.
|
|
||||||
UV_STACK_SIZE: 3000000 # 3 megabyte, triple the default on windows
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -82,18 +82,6 @@ cargo run -- venv
|
||||||
cargo run -- pip install requests
|
cargo run -- pip install requests
|
||||||
```
|
```
|
||||||
|
|
||||||
### Testing on Windows
|
|
||||||
|
|
||||||
When testing debug builds on Windows, the stack can overflow resulting in a `STATUS_STACK_OVERFLOW`
|
|
||||||
error code. This is due to a small stack size limit on Windows that we encounter when running
|
|
||||||
unoptimized builds — the release builds do not have this problem. We
|
|
||||||
[added a `UV_STACK_SIZE` variable](https://github.com/astral-sh/uv/pull/941) to bypass this problem
|
|
||||||
during testing. We recommend bumping the stack size from the default of 1MB to 3MB, for example:
|
|
||||||
|
|
||||||
```powershell
|
|
||||||
$Env:UV_STACK_SIZE = '3000000'
|
|
||||||
```
|
|
||||||
|
|
||||||
## Running inside a Docker container
|
## Running inside a Docker container
|
||||||
|
|
||||||
Source distributions can run arbitrary code on build and can make unwanted modifications to your
|
Source distributions can run arbitrary code on build and can make unwanted modifications to your
|
||||||
|
|
|
||||||
|
|
@ -249,9 +249,6 @@ impl EnvVars {
|
||||||
/// Use to disable line wrapping for diagnostics.
|
/// Use to disable line wrapping for diagnostics.
|
||||||
pub const UV_NO_WRAP: &'static str = "UV_NO_WRAP";
|
pub const UV_NO_WRAP: &'static str = "UV_NO_WRAP";
|
||||||
|
|
||||||
/// Use to increase the stack size used by uv in debug builds on Windows.
|
|
||||||
pub const UV_STACK_SIZE: &'static str = "UV_STACK_SIZE";
|
|
||||||
|
|
||||||
/// Generates the environment variable key for the HTTP Basic authentication username.
|
/// Generates the environment variable key for the HTTP Basic authentication username.
|
||||||
#[attr_env_var_pattern("UV_INDEX_{name}_USERNAME")]
|
#[attr_env_var_pattern("UV_INDEX_{name}_USERNAME")]
|
||||||
pub fn index_username(name: &str) -> String {
|
pub fn index_username(name: &str) -> String {
|
||||||
|
|
@ -505,6 +502,15 @@ impl EnvVars {
|
||||||
/// for more.
|
/// for more.
|
||||||
pub const RUST_LOG: &'static str = "RUST_LOG";
|
pub const RUST_LOG: &'static str = "RUST_LOG";
|
||||||
|
|
||||||
|
/// Use to set the stack size used by uv.
|
||||||
|
///
|
||||||
|
/// The value is in bytes, and the default is typically 2MB (2097152).
|
||||||
|
/// Unlike the normal `RUST_MIN_STACK` semantics, this can affect main thread
|
||||||
|
/// stack size, because we actually spawn our own main2 thread to work around
|
||||||
|
/// the fact that Windows' real main thread is only 1MB. That thread has size
|
||||||
|
/// `max(RUST_MIN_STACK, 4MB)`.
|
||||||
|
pub const RUST_MIN_STACK: &'static str = "RUST_MIN_STACK";
|
||||||
|
|
||||||
/// The directory containing the `Cargo.toml` manifest for a package.
|
/// The directory containing the `Cargo.toml` manifest for a package.
|
||||||
#[attr_hidden]
|
#[attr_hidden]
|
||||||
pub const CARGO_MANIFEST_DIR: &'static str = "CARGO_MANIFEST_DIR";
|
pub const CARGO_MANIFEST_DIR: &'static str = "CARGO_MANIFEST_DIR";
|
||||||
|
|
|
||||||
|
|
@ -1819,17 +1819,32 @@ where
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Windows has a default stack size of 1MB, which is lower than the linux and mac default.
|
// Running out of stack has been an issue for us. We box types and futures in various places
|
||||||
|
// to mitigate this, with this being an especially important case.
|
||||||
|
//
|
||||||
|
// Non-main threads should all have 2MB, as Rust forces platform consistency there,
|
||||||
|
// but that can be overridden with the RUST_MIN_STACK environment variable if you need more.
|
||||||
|
//
|
||||||
|
// Main thread stack-size is the real issue. There's BIG variety here across platforms
|
||||||
|
// and it's harder to control (which is why Rust doesn't by default). Notably
|
||||||
|
// on macOS and Linux you will typically get 8MB main thread, while on Windows you will
|
||||||
|
// typically get 1MB, which is *tiny*:
|
||||||
// https://learn.microsoft.com/en-us/cpp/build/reference/stack-stack-allocations?view=msvc-170
|
// https://learn.microsoft.com/en-us/cpp/build/reference/stack-stack-allocations?view=msvc-170
|
||||||
// We support increasing the stack size to avoid stack overflows in debug mode on Windows. In
|
//
|
||||||
// addition, we box types and futures in various places. This includes the `Box::pin(run())`
|
// To normalize this we just spawn a new thread called main2 with a size we can set
|
||||||
// here, which prevents the large (non-send) main future alone from overflowing the stack.
|
// ourselves. 2MB is typically too small (especially for our debug builds), while 4MB
|
||||||
let result = if let Ok(stack_size) = std::env::var(EnvVars::UV_STACK_SIZE) {
|
// seems fine. Also we still try to respect RUST_MIN_STACK if it's set, in case useful,
|
||||||
let stack_size = stack_size.parse().expect("Invalid stack size");
|
// but don't let it ask for a smaller stack to avoid messy misconfiguration since we
|
||||||
let tokio_main = move || {
|
// know we use quite a bit of main stack space.
|
||||||
|
let main_stack_size = std::env::var(EnvVars::RUST_MIN_STACK)
|
||||||
|
.ok()
|
||||||
|
.and_then(|var| var.parse::<usize>().ok())
|
||||||
|
.unwrap_or(0)
|
||||||
|
.max(4 * 1024 * 1024);
|
||||||
|
|
||||||
|
let main2 = move || {
|
||||||
let runtime = tokio::runtime::Builder::new_current_thread()
|
let runtime = tokio::runtime::Builder::new_current_thread()
|
||||||
.enable_all()
|
.enable_all()
|
||||||
.thread_stack_size(stack_size)
|
|
||||||
.build()
|
.build()
|
||||||
.expect("Failed building the Runtime");
|
.expect("Failed building the Runtime");
|
||||||
// Box the large main future to avoid stack overflows.
|
// Box the large main future to avoid stack overflows.
|
||||||
|
|
@ -1842,22 +1857,13 @@ where
|
||||||
runtime.shutdown_background();
|
runtime.shutdown_background();
|
||||||
result
|
result
|
||||||
};
|
};
|
||||||
std::thread::Builder::new()
|
let result = std::thread::Builder::new()
|
||||||
.stack_size(stack_size)
|
.name("main2".to_owned())
|
||||||
.spawn(tokio_main)
|
.stack_size(main_stack_size)
|
||||||
|
.spawn(main2)
|
||||||
.expect("Tokio executor failed, was there a panic?")
|
.expect("Tokio executor failed, was there a panic?")
|
||||||
.join()
|
.join()
|
||||||
.expect("Tokio executor failed, was there a panic?")
|
.expect("Tokio executor failed, was there a panic?");
|
||||||
} else {
|
|
||||||
let runtime = tokio::runtime::Builder::new_current_thread()
|
|
||||||
.enable_all()
|
|
||||||
.build()
|
|
||||||
.expect("Failed building the Runtime");
|
|
||||||
// Box the large main future to avoid stack overflows.
|
|
||||||
let result = runtime.block_on(Box::pin(run(cli)));
|
|
||||||
runtime.shutdown_background();
|
|
||||||
result
|
|
||||||
};
|
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
Ok(code) => code.into(),
|
Ok(code) => code.into(),
|
||||||
|
|
|
||||||
|
|
@ -489,12 +489,6 @@ impl TestContext {
|
||||||
// Avoid locale issues in tests
|
// Avoid locale issues in tests
|
||||||
command.env(EnvVars::LC_ALL, "C");
|
command.env(EnvVars::LC_ALL, "C");
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg!(all(windows, debug_assertions)) {
|
|
||||||
// TODO(konstin): Reduce stack usage in debug mode enough that the tests pass with the
|
|
||||||
// default windows stack of 1MB
|
|
||||||
command.env(EnvVars::UV_STACK_SIZE, (4 * 1024 * 1024).to_string());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a `pip compile` command for testing.
|
/// Create a `pip compile` command for testing.
|
||||||
|
|
@ -581,13 +575,6 @@ impl TestContext {
|
||||||
let mut command = self.new_command();
|
let mut command = self.new_command();
|
||||||
command.arg("help");
|
command.arg("help");
|
||||||
command.env_remove(EnvVars::UV_CACHE_DIR);
|
command.env_remove(EnvVars::UV_CACHE_DIR);
|
||||||
|
|
||||||
if cfg!(all(windows, debug_assertions)) {
|
|
||||||
// TODO(konstin): Reduce stack usage in debug mode enough that the tests pass with the
|
|
||||||
// default windows stack of 1MB
|
|
||||||
command.env(EnvVars::UV_STACK_SIZE, (4 * 1024 * 1024).to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
command
|
command
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -636,13 +623,6 @@ impl TestContext {
|
||||||
pub fn publish(&self) -> Command {
|
pub fn publish(&self) -> Command {
|
||||||
let mut command = self.new_command();
|
let mut command = self.new_command();
|
||||||
command.arg("publish");
|
command.arg("publish");
|
||||||
|
|
||||||
if cfg!(all(windows, debug_assertions)) {
|
|
||||||
// TODO(konstin): Reduce stack usage in debug mode enough that the tests pass with the
|
|
||||||
// default windows stack of 1MB
|
|
||||||
command.env(EnvVars::UV_STACK_SIZE, (4 * 1024 * 1024).to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
command
|
command
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -104,11 +104,6 @@ fn lock_ecosystem_package(python_version: &str, name: &str) -> Result<()> {
|
||||||
.env(EnvVars::UV_EXCLUDE_NEWER, EXCLUDE_NEWER)
|
.env(EnvVars::UV_EXCLUDE_NEWER, EXCLUDE_NEWER)
|
||||||
.current_dir(context.temp_dir.path());
|
.current_dir(context.temp_dir.path());
|
||||||
|
|
||||||
if cfg!(all(windows, debug_assertions)) {
|
|
||||||
// TODO(konstin): Reduce stack usage in debug mode enough that the tests pass with the
|
|
||||||
// default windows stack of 1MB
|
|
||||||
command.env(EnvVars::UV_STACK_SIZE, (4 * 1024 * 1024).to_string());
|
|
||||||
}
|
|
||||||
let (snapshot, _) = common::run_and_format(
|
let (snapshot, _) = common::run_and_format(
|
||||||
&mut command,
|
&mut command,
|
||||||
context.filters(),
|
context.filters(),
|
||||||
|
|
|
||||||
|
|
@ -24,13 +24,6 @@ fn add_shared_args(mut command: Command, cwd: &Path) -> Command {
|
||||||
// Avoid locale issues in tests
|
// Avoid locale issues in tests
|
||||||
command.env(EnvVars::LC_ALL, "C");
|
command.env(EnvVars::LC_ALL, "C");
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg!(all(windows, debug_assertions)) {
|
|
||||||
// TODO(konstin): Reduce stack usage in debug mode enough that the tests pass with the
|
|
||||||
// default windows stack of 1MB
|
|
||||||
command.env(EnvVars::UV_STACK_SIZE, (4 * 1024 * 1024).to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
command
|
command
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -320,10 +320,6 @@ uv will require that all dependencies have a hash specified in the requirements
|
||||||
Equivalent to the `--resolution` command-line argument. For example, if set to
|
Equivalent to the `--resolution` command-line argument. For example, if set to
|
||||||
`lowest-direct`, uv will install the lowest compatible versions of all direct dependencies.
|
`lowest-direct`, uv will install the lowest compatible versions of all direct dependencies.
|
||||||
|
|
||||||
### `UV_STACK_SIZE`
|
|
||||||
|
|
||||||
Use to increase the stack size used by uv in debug builds on Windows.
|
|
||||||
|
|
||||||
### `UV_SYSTEM_PYTHON`
|
### `UV_SYSTEM_PYTHON`
|
||||||
|
|
||||||
Equivalent to the `--system` command-line argument. If set to `true`, uv will
|
Equivalent to the `--system` command-line argument. If set to `true`, uv will
|
||||||
|
|
@ -484,6 +480,16 @@ For example:
|
||||||
See the [tracing documentation](https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html#example-syntax)
|
See the [tracing documentation](https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html#example-syntax)
|
||||||
for more.
|
for more.
|
||||||
|
|
||||||
|
### `RUST_MIN_STACK`
|
||||||
|
|
||||||
|
Use to set the stack size used by uv.
|
||||||
|
|
||||||
|
The value is in bytes, and the default is typically 2MB (2097152).
|
||||||
|
Unlike the normal `RUST_MIN_STACK` semantics, this can affect main thread
|
||||||
|
stack size, because we actually spawn our own main2 thread to work around
|
||||||
|
the fact that Windows' real main thread is only 1MB. That thread has size
|
||||||
|
`max(RUST_MIN_STACK, 4MB)`.
|
||||||
|
|
||||||
### `SHELL`
|
### `SHELL`
|
||||||
|
|
||||||
The standard `SHELL` posix env var.
|
The standard `SHELL` posix env var.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue