@@ -16,6 +16,8 @@ use core::mem::{self, MaybeUninit};
1616use core:: ops:: Range ;
1717use core:: ptr:: { self , NonNull } ;
1818use core:: sync:: atomic:: { AtomicUsize , Ordering } ;
19+ use rustix:: mm:: { MapFlags , ProtFlags , mmap_anonymous, munmap} ;
20+ use rustix:: param:: page_size;
1921use wasmtime_environ:: {
2022 BuiltinFunctionIndex , DefinedGlobalIndex , DefinedMemoryIndex , DefinedTableIndex ,
2123 DefinedTagIndex , VMCONTEXT_MAGIC , VMSharedTypeIndex , WasmHeapTopType , WasmValType ,
@@ -1093,6 +1095,13 @@ pub struct VMStoreContext {
10931095 /// yield if running asynchronously.
10941096 pub epoch_deadline : UnsafeCell < u64 > ,
10951097
1098+ /// The page of virtual memory used to signal that it's time to switch
1099+ /// tasks. Compiled guest code regularly attempts a read at this address.
1100+ /// When it is time to switch, the host uses mprotect() to forbid reads. The
1101+ /// fault soon caused by guest code then lands in the signal handler, which
1102+ /// effects a switch and resets the page permissions.
1103+ pub epoch_interrupt_page_ptr : Option < VmPtr < c_void > > , // ptr-sized
1104+
10961105 /// Current stack limit of the wasm module.
10971106 ///
10981107 /// For more information see `crates/cranelift/src/lib.rs`.
@@ -1175,6 +1184,23 @@ impl Default for VMStoreContext {
11751184 VMStoreContext {
11761185 fuel_consumed : UnsafeCell :: new ( 0 ) ,
11771186 epoch_deadline : UnsafeCell :: new ( 0 ) ,
1187+ // TODO: Allocate this only when epoch_interruption_via_mmu is on.
1188+ // Probably set it to None here and allocate it elsewhere.
1189+ epoch_interrupt_page_ptr : unsafe {
1190+ let page_ptr = mmap_anonymous (
1191+ ptr:: null_mut ( ) , // Let the kernel pick location.
1192+ page_size ( ) ,
1193+ ProtFlags :: READ ,
1194+ // Privacy doesn't matter, as we never write to the
1195+ // interrupt page. However, private is the safer choice in
1196+ // case someone starts doing so.
1197+ MapFlags :: PRIVATE ,
1198+ )
1199+ . expect ( "an interrupt page should be allocable" ) ;
1200+ let non_null_page_ptr = NonNull :: new ( page_ptr)
1201+ . expect ( "if mmap returns successfully, its result should not be null" ) ;
1202+ Some ( non_null_page_ptr. into ( ) )
1203+ } ,
11781204 stack_limit : UnsafeCell :: new ( usize:: max_value ( ) ) ,
11791205 gc_heap : VMMemoryDefinition {
11801206 base : NonNull :: dangling ( ) . into ( ) ,
@@ -1189,6 +1215,17 @@ impl Default for VMStoreContext {
11891215 }
11901216}
11911217
1218+ // TODO: Kill this and find somewhere else to munmap it, because VMStoreContext
1219+ // is documented as being pod-type above.
1220+ // impl Drop for VMStoreContext {
1221+ // fn drop(&mut self) {
1222+ // unsafe {
1223+ // munmap(self.epoch_interrupt_page_ptr, page_size())
1224+ // .expect("should be able to unmap interrupt page");
1225+ // }
1226+ // }
1227+ // }
1228+
11921229#[ cfg( test) ]
11931230mod test_vmstore_context {
11941231 use super :: { VMMemoryDefinition , VMStoreContext } ;
0 commit comments