@@ -46,6 +46,24 @@ use std::time::Instant;
4646
4747use crate :: { Preopen , Sandbox } ;
4848
49+ /// Default Hyperlight's surrogate-process pool to 1 on Windows.
50+ ///
51+ /// The surrogate-process manager pre-spawns `HYPERLIGHT_INITIAL_SURROGATES`
52+ /// Windows processes (default 512) the first time any sandbox is created.
53+ /// At ~7 ms per `CreateProcessA` that is ~3.5 s of latency that library
54+ /// callers would pay on the very first sandbox. Pinning the default to 1
55+ /// drops that to ~7 ms. Callers (or the embedding binary) can still
56+ /// override by setting the env var before calling into `pyhl`.
57+ fn default_surrogate_count ( ) {
58+ if std:: env:: var_os ( "HYPERLIGHT_INITIAL_SURROGATES" ) . is_none ( ) {
59+ // Safety: must be called before any sandbox is created and
60+ // before additional threads are spawned.
61+ unsafe {
62+ std:: env:: set_var ( "HYPERLIGHT_INITIAL_SURROGATES" , "1" ) ;
63+ }
64+ }
65+ }
66+
4967/// Standard file names inside an image home.
5068pub const KERNEL_FILE : & str = "kernel" ;
5169/// Standard file names inside an image home.
@@ -104,6 +122,7 @@ pub struct InstallReport {
104122/// are local file copies. See [`InstallSource`] for each variant's
105123/// semantics.
106124pub fn install ( opts : & InstallOptions < ' _ > ) -> Result < InstallReport > {
125+ default_surrogate_count ( ) ;
107126 let home = opts. home . to_path_buf ( ) ;
108127 let dst_kernel = home. join ( KERNEL_FILE ) ;
109128 let dst_initrd = home. join ( INITRD_FILE ) ;
@@ -216,6 +235,7 @@ impl Runtime {
216235 /// directories to expose under the guest paths that were baked in
217236 /// at `install` time.
218237 pub fn new ( home : & Path , mounts : & [ Preopen ] ) -> Result < Self > {
238+ default_surrogate_count ( ) ;
219239 let snap = home. join ( SNAPSHOT_FILE ) ;
220240 if !snap. is_file ( ) {
221241 bail ! (
0 commit comments