From dd715b0905865d10380e3d05853bd2e44bd58773 Mon Sep 17 00:00:00 2001 From: Chris Young Date: Sun, 27 Sep 2026 07:39:00 -0700 Subject: [PATCH] Fix Windows startup stack overflow Windows reserves a 1 MiB main-thread stack by default. OctoSense's startup evaluates and constructs a large Makepad script/widget tree on that thread and exited with STATUS_STACK_OVERFLOW before the first window. build.rs reserves 16 MiB for the executable's main thread on Windows MSVC (/STACK:16777216; PE stack pages are committed lazily). Unix-only process cleanup imports and variables are gated so the Windows build stops warning. Originally OctoSense-Desktop#10 by Chris Young, validated on Windows (D3D11 first frame, --gallery, dumpbin shows a 0x1000000 stack reserve); ported onto current main. Co-Authored-By: Claude Opus 5.5 (1M context) --- build.rs | 12 ++++++++++++ src/clients.rs | 9 ++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 build.rs diff --git a/build.rs b/build.rs new file mode 100644 index 00000000..dbb00aac --- /dev/null +++ b/build.rs @@ -0,0 +1,12 @@ +// Windows reserves only 1 MiB for the main thread by default. OctoSense's +// startup evaluates and constructs a large Makepad script/widget tree on that +// thread, whose bounded peak exceeds the default before the first window is +// shown. /STACK changes the PE address-space reserve; pages are still committed +// only as they are used. +fn main() { + let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap_or_default(); + let target_env = std::env::var("CARGO_CFG_TARGET_ENV").unwrap_or_default(); + if target_os == "windows" && target_env == "msvc" { + println!("cargo:rustc-link-arg-bins=/STACK:16777216"); + } +} diff --git a/src/clients.rs b/src/clients.rs index c56cb4fa..22c247e4 100644 --- a/src/clients.rs +++ b/src/clients.rs @@ -28,7 +28,10 @@ use crate::host; #[cfg(unix)] use std::os::unix::process::CommandExt; -use makepad_widgets::makepad_platform::thread::{CancellationToken, Lane, SignalToUI, TaskPool, ThreadSpawner, ThreadOptions}; +#[cfg(unix)] +use makepad_widgets::makepad_platform::thread::CancellationToken; +use makepad_widgets::makepad_platform::thread::{Lane, SignalToUI, TaskPool, ThreadSpawner, ThreadOptions}; +#[cfg(any(unix, test))] use makepad_widgets::Cx; use crate::hub::ClientId; @@ -643,7 +646,7 @@ pub fn kill_child_group(child: &mut Child, _grace: std::time::Duration, _pool: & /// Final slot teardown owns the child from here on. Signal and reap it wholly /// on a heavy pool worker; dropping a slot on the UI thread never waits for a /// process or decoder wrapper to exit. -fn reap_child_group(mut child: Child, grace: std::time::Duration, pool: &TaskPool) { +fn reap_child_group(mut child: Child, _grace: std::time::Duration, pool: &TaskPool) { #[cfg(unix)] let pid = { let pid = child.id() as i32; @@ -656,7 +659,7 @@ fn reap_child_group(mut child: Child, grace: std::time::Duration, pool: &TaskPoo #[cfg(unix)] { let wait = CancellationToken::new(); - let _ = wait.wait_until(Cx::monotonic_now() + grace.as_secs_f64()); + let _ = wait.wait_until(Cx::monotonic_now() + _grace.as_secs_f64()); if signal::alive(-pid) { signal::kill_group(pid, signal::SIGKILL); }