@@ -17,7 +17,9 @@ use crate::{
1717 signal:: Signal ,
1818 storage:: metered:: Storage as MeteredStorage ,
1919 telemetry:: metrics:: task:: Label ,
20- utils:: { add_attribute, signal:: Stopper , supervision:: Tree , Panicker , Registry , ScopeGuard } ,
20+ utils:: {
21+ self , add_attribute, signal:: Stopper , supervision:: Tree , Panicker , Registry , ScopeGuard ,
22+ } ,
2123 BufferPool , BufferPoolConfig , Clock , Error , Execution , Handle , Metrics as _, SinkOf ,
2224 Spawner as _, StreamOf , METRICS_PREFIX ,
2325} ;
@@ -42,7 +44,6 @@ use std::{
4244 num:: NonZeroUsize ,
4345 path:: PathBuf ,
4446 sync:: Arc ,
45- thread,
4647 time:: { Duration , SystemTime } ,
4748} ;
4849use tokio:: runtime:: { Builder , Runtime } ;
@@ -141,6 +142,14 @@ pub struct Config {
141142 /// operations that require blocking (like `fs` and writing to `Stdout`).
142143 max_blocking_threads : usize ,
143144
145+ /// Stack size to use for runtime-owned threads.
146+ ///
147+ /// Defaults to the system stack size when the current platform exposes it,
148+ /// and otherwise falls back to Rust's default spawned-thread stack size.
149+ ///
150+ /// See [utils::thread::system_thread_stack_size].
151+ thread_stack_size : usize ,
152+
144153 /// Whether or not to catch panics.
145154 catch_panics : bool ,
146155
@@ -170,6 +179,7 @@ impl Config {
170179 Self {
171180 worker_threads : 2 ,
172181 max_blocking_threads : 512 ,
182+ thread_stack_size : utils:: thread:: system_thread_stack_size ( ) ,
173183 catch_panics : false ,
174184 storage_directory,
175185 maximum_buffer_size : 2 * 1024 * 1024 , // 2 MB
@@ -191,6 +201,11 @@ impl Config {
191201 self
192202 }
193203 /// See [Config]
204+ pub const fn with_thread_stack_size ( mut self , n : usize ) -> Self {
205+ self . thread_stack_size = n;
206+ self
207+ }
208+ /// See [Config]
194209 pub const fn with_catch_panics ( mut self , b : bool ) -> Self {
195210 self . catch_panics = b;
196211 self
@@ -241,6 +256,10 @@ impl Config {
241256 self . max_blocking_threads
242257 }
243258 /// See [Config]
259+ pub const fn thread_stack_size ( & self ) -> usize {
260+ self . thread_stack_size
261+ }
262+ /// See [Config]
244263 pub const fn catch_panics ( & self ) -> bool {
245264 self . catch_panics
246265 }
@@ -297,6 +316,7 @@ pub struct Executor {
297316 runtime : Runtime ,
298317 shutdown : Mutex < Stopper > ,
299318 panicker : Panicker ,
319+ thread_stack_size : usize ,
300320}
301321
302322/// Implementation of [crate::Runner] for the `tokio` runtime.
@@ -334,6 +354,7 @@ impl crate::Runner for Runner {
334354 let runtime = Builder :: new_multi_thread ( )
335355 . worker_threads ( self . cfg . worker_threads )
336356 . max_blocking_threads ( self . cfg . max_blocking_threads )
357+ . thread_stack_size ( self . cfg . thread_stack_size )
337358 . enable_all ( )
338359 . build ( )
339360 . expect ( "failed to create Tokio runtime" ) ;
@@ -368,6 +389,7 @@ impl crate::Runner for Runner {
368389 IoUringConfig {
369390 storage_directory: self . cfg. storage_directory. clone( ) ,
370391 iouring_config: Default :: default ( ) ,
392+ thread_stack_size: self . cfg. thread_stack_size,
371393 } ,
372394 iouring_registry,
373395 storage_buffer_pool. clone( ) ,
@@ -404,6 +426,7 @@ impl crate::Runner for Runner {
404426 shutdown_timeout: Some ( self . cfg. network_cfg. read_write_timeout) ,
405427 ..Default :: default ( )
406428 } ,
429+ thread_stack_size: self . cfg. thread_stack_size,
407430 ..Default :: default ( )
408431 } ;
409432 let network = MeteredNetwork :: new(
@@ -435,6 +458,7 @@ impl crate::Runner for Runner {
435458 runtime,
436459 shutdown : Mutex :: new ( Stopper :: default ( ) ) ,
437460 panicker,
461+ thread_stack_size : self . cfg . thread_stack_size ,
438462 } ) ;
439463
440464 // Get metrics
@@ -578,7 +602,7 @@ impl crate::Spawner for Context {
578602 ) ;
579603
580604 if matches ! ( past, Execution :: Dedicated ) {
581- thread:: spawn ( {
605+ utils :: thread:: spawn ( executor . thread_stack_size , {
582606 // Ensure the task can access the tokio runtime
583607 let handle = executor. runtime . handle ( ) . clone ( ) ;
584608 move || {
@@ -871,6 +895,21 @@ mod tests {
871895 ) ;
872896 }
873897
898+ #[ test]
899+ fn test_default_thread_stack_size_uses_system_default ( ) {
900+ let cfg = Config :: new ( ) ;
901+ assert_eq ! (
902+ cfg. thread_stack_size( ) ,
903+ utils:: thread:: system_thread_stack_size( )
904+ ) ;
905+ }
906+
907+ #[ test]
908+ fn test_thread_stack_size_override ( ) {
909+ let cfg = Config :: new ( ) . with_thread_stack_size ( 4 * 1024 * 1024 ) ;
910+ assert_eq ! ( cfg. thread_stack_size( ) , 4 * 1024 * 1024 ) ;
911+ }
912+
874913 #[ test]
875914 fn test_explicit_buffer_pool_configs_override_worker_threads ( ) {
876915 // Order does not matter -- explicit configs always win.
0 commit comments