diff --git a/src/bin/webcodex-server.rs b/src/bin/webcodex-server.rs index 6f4b0371..a68bfb37 100644 --- a/src/bin/webcodex-server.rs +++ b/src/bin/webcodex-server.rs @@ -1,9 +1,22 @@ use webcodex::{server_binary_action, ServerBinaryAction}; -#[tokio::main] -async fn main() -> Result<(), Box> { +// The default macOS Tokio worker stack is too small for the deepest MCP request +// path exercised by the local Server. Keep this explicit instead of requiring +// callers to set RUST_MIN_STACK for `webcodex share`. +#[cfg(target_os = "macos")] +const MACOS_SERVER_RUNTIME_STACK_SIZE: usize = 8 * 1024 * 1024; + +fn build_server_runtime() -> std::io::Result { + let mut builder = tokio::runtime::Builder::new_multi_thread(); + builder.enable_all(); + #[cfg(target_os = "macos")] + builder.thread_stack_size(MACOS_SERVER_RUNTIME_STACK_SIZE); + builder.build() +} + +fn main() -> Result<(), Box> { match server_binary_action(std::env::args().skip(1)) { - ServerBinaryAction::Run => webcodex::run_server().await, + ServerBinaryAction::Run => build_server_runtime()?.block_on(webcodex::run_server()), ServerBinaryAction::Exit { code, stdout, @@ -19,3 +32,26 @@ async fn main() -> Result<(), Box> { } } } + +#[cfg(all(test, target_os = "macos"))] +mod tests { + use super::*; + + #[test] + fn server_runtime_uses_large_worker_stack() { + let runtime = build_server_runtime().expect("build WebCodex Server runtime"); + let stack_size = runtime.block_on(async { + tokio::spawn(async { + // SAFETY: pthread_self returns the current worker thread and + // pthread_get_stacksize_np only queries that thread's stack metadata. + unsafe { libc::pthread_get_stacksize_np(libc::pthread_self()) } + }) + .await + .expect("observe WebCodex Server worker") + }); + assert!( + stack_size >= MACOS_SERVER_RUNTIME_STACK_SIZE, + "WebCodex Server worker stack was {stack_size} bytes; expected at least {MACOS_SERVER_RUNTIME_STACK_SIZE}" + ); + } +}