@@ -33,6 +33,8 @@ use crate::mem::memory_region::{DEFAULT_GUEST_BLOB_MEM_FLAGS, MemoryRegionFlags}
3333use crate :: mem:: mgr:: SandboxMemoryManager ;
3434use crate :: mem:: shared_mem:: ExclusiveSharedMemory ;
3535#[ cfg( feature = "nanvix-unstable" ) ]
36+ use crate :: mem:: shared_mem:: HostSharedMemory ;
37+ #[ cfg( feature = "nanvix-unstable" ) ]
3638use crate :: mem:: shared_mem:: SharedMemory ;
3739use crate :: sandbox:: SandboxConfiguration ;
3840use crate :: { MultiUseSandbox , Result , new_error} ;
@@ -70,11 +72,9 @@ pub(crate) struct SandboxRuntimeConfig {
7072/// `decrement()` take `&self` rather than `&mut self`.
7173///
7274/// The counter holds an `Arc<Mutex<Option<HostSharedMemory>>>` that is
73- /// shared with [`ExclusiveSharedMemory`]. The `Option` is `None` until
74- /// [`build()`](ExclusiveSharedMemory::build) populates it, at which point
75- /// the counter can issue volatile writes via the proper protocol. This
76- /// avoids adding lock overhead to `ExclusiveSharedMemory` during the
77- /// exclusive setup phase.
75+ /// shared with [`UninitializedSandbox`]. The `Option` is `None` until
76+ /// [`evolve()`](UninitializedSandbox::evolve) populates it, at which point
77+ /// the counter can issue volatile writes via the proper protocol.
7878///
7979/// Only one `GuestCounter` may be created per sandbox; a second call to
8080/// [`UninitializedSandbox::guest_counter()`] returns an error.
@@ -85,7 +85,7 @@ pub struct GuestCounter {
8585
8686#[ cfg( feature = "nanvix-unstable" ) ]
8787struct GuestCounterInner {
88- deferred_hshm : Arc < Mutex < Option < crate :: mem :: shared_mem :: HostSharedMemory > > > ,
88+ deferred_hshm : Arc < Mutex < Option < HostSharedMemory > > > ,
8989 offset : usize ,
9090 value : u64 ,
9191}
@@ -111,11 +111,12 @@ impl GuestCounter {
111111 } ) ?
112112 . clone ( )
113113 } ;
114- inner . value = inner
114+ let new_value = inner
115115 . value
116116 . checked_add ( 1 )
117117 . ok_or_else ( || new_error ! ( "GuestCounter overflow" ) ) ?;
118- shm. write :: < u64 > ( inner. offset , inner. value ) ?;
118+ shm. write :: < u64 > ( inner. offset , new_value) ?;
119+ inner. value = new_value;
119120 Ok ( ( ) )
120121 }
121122
@@ -131,11 +132,12 @@ impl GuestCounter {
131132 } ) ?
132133 . clone ( )
133134 } ;
134- inner . value = inner
135+ let new_value = inner
135136 . value
136137 . checked_sub ( 1 )
137138 . ok_or_else ( || new_error ! ( "GuestCounter underflow" ) ) ?;
138- shm. write :: < u64 > ( inner. offset , inner. value ) ?;
139+ shm. write :: < u64 > ( inner. offset , new_value) ?;
140+ inner. value = new_value;
139141 Ok ( ( ) )
140142 }
141143
@@ -170,6 +172,17 @@ pub struct UninitializedSandbox {
170172 // This is needed to convey the stack pointer between the snapshot
171173 // and the HyperlightVm creation
172174 pub ( crate ) stack_top_gva : u64 ,
175+ /// Populated by [`evolve()`](Self::evolve) with a [`HostSharedMemory`]
176+ /// view of scratch memory. Code that needs host-style volatile access
177+ /// before `evolve()` (e.g. `GuestCounter`) can clone this `Arc` and
178+ /// will see `Some` once `evolve()` completes.
179+ #[ cfg( feature = "nanvix-unstable" ) ]
180+ pub ( crate ) deferred_hshm : Arc < Mutex < Option < HostSharedMemory > > > ,
181+ /// Set to `true` once a [`GuestCounter`] has been handed out via
182+ /// [`guest_counter()`](Self::guest_counter). Prevents creating
183+ /// multiple counters that would have divergent cached values.
184+ #[ cfg( feature = "nanvix-unstable" ) ]
185+ counter_taken : std:: sync:: atomic:: AtomicBool ,
173186}
174187
175188impl Debug for UninitializedSandbox {
@@ -267,10 +280,9 @@ impl UninitializedSandbox {
267280 /// the top of scratch memory, so both host and guest can locate it
268281 /// without an explicit GPA parameter.
269282 ///
270- /// The returned counter holds an `Arc` clone of the scratch memory 's
283+ /// The returned counter holds an `Arc` clone of the sandbox 's
271284 /// `deferred_hshm`, so it will automatically gain access to the
272- /// [`HostSharedMemory`] once [`build()`](ExclusiveSharedMemory::build)
273- /// is called during [`evolve()`](Self::evolve).
285+ /// [`HostSharedMemory`] once [`evolve()`](Self::evolve) completes.
274286 ///
275287 /// This method can only be called once; a second call returns an error
276288 /// because multiple counters would have divergent cached values.
@@ -280,12 +292,7 @@ impl UninitializedSandbox {
280292
281293 use hyperlight_common:: layout:: SCRATCH_TOP_GUEST_COUNTER_OFFSET ;
282294
283- if self
284- . mgr
285- . scratch_mem
286- . counter_taken
287- . swap ( true , Ordering :: Relaxed )
288- {
295+ if self . counter_taken . swap ( true , Ordering :: Relaxed ) {
289296 return Err ( new_error ! (
290297 "GuestCounter has already been created for this sandbox"
291298 ) ) ;
@@ -301,7 +308,7 @@ impl UninitializedSandbox {
301308 }
302309
303310 let offset = scratch_size - SCRATCH_TOP_GUEST_COUNTER_OFFSET as usize ;
304- let deferred_hshm = self . mgr . scratch_mem . deferred_hshm . clone ( ) ;
311+ let deferred_hshm = self . deferred_hshm . clone ( ) ;
305312
306313 Ok ( GuestCounter {
307314 inner : Mutex :: new ( GuestCounterInner {
@@ -370,6 +377,10 @@ impl UninitializedSandbox {
370377 rt_cfg,
371378 load_info : snapshot. load_info ( ) ,
372379 stack_top_gva : snapshot. stack_top_gva ( ) ,
380+ #[ cfg( feature = "nanvix-unstable" ) ]
381+ deferred_hshm : Arc :: new ( Mutex :: new ( None ) ) ,
382+ #[ cfg( feature = "nanvix-unstable" ) ]
383+ counter_taken : std:: sync:: atomic:: AtomicBool :: new ( false ) ,
373384 } ;
374385
375386 // If we were passed a writer for host print register it otherwise use the default.
@@ -449,6 +460,18 @@ impl UninitializedSandbox {
449460 ) -> Result < ( ) > {
450461 self . register ( "HostPrint" , print_func)
451462 }
463+
464+ /// Populate the deferred `HostSharedMemory` slot without running
465+ /// the full `evolve()` pipeline. Used in tests where guest boot
466+ /// is not available.
467+ #[ cfg( all( test, feature = "nanvix-unstable" ) ) ]
468+ fn simulate_build ( & self ) {
469+ let hshm = self . mgr . scratch_mem . as_host_shared_memory ( ) ;
470+ #[ allow( clippy:: unwrap_used) ]
471+ {
472+ * self . deferred_hshm . lock ( ) . unwrap ( ) = Some ( hshm) ;
473+ }
474+ }
452475}
453476// Check to see if the current version of Windows is supported
454477// Hyperlight is only supported on Windows 11 and Windows Server 2022 and later
@@ -1500,7 +1523,7 @@ mod tests {
15001523 fn increment_decrement ( ) {
15011524 let mut sandbox = make_sandbox ( ) ;
15021525 let counter = sandbox. guest_counter ( ) . unwrap ( ) ;
1503- sandbox. mgr . scratch_mem . simulate_build ( ) ;
1526+ sandbox. simulate_build ( ) ;
15041527
15051528 counter. increment ( ) . unwrap ( ) ;
15061529 assert_eq ! ( counter. value( ) . unwrap( ) , 1 ) ;
@@ -1514,7 +1537,7 @@ mod tests {
15141537 fn underflow_returns_error ( ) {
15151538 let mut sandbox = make_sandbox ( ) ;
15161539 let counter = sandbox. guest_counter ( ) . unwrap ( ) ;
1517- sandbox. mgr . scratch_mem . simulate_build ( ) ;
1540+ sandbox. simulate_build ( ) ;
15181541
15191542 assert_eq ! ( counter. value( ) . unwrap( ) , 0 ) ;
15201543 let result = counter. decrement ( ) ;
0 commit comments