Add some documentation to UffdRegion
@@ -19,6 +19,32 @@ use std::sync::{Arc, Mutex, Weak};
use std::thread::{self, JoinHandle};
use userfaultfd::{IoctlFlags, Uffd, UffdBuilder};
+/// A [`Region`](../trait.Region.html) backed by `mmap` and managed by `userfaultfd`.
+///
+/// Much like [`MmapRegion`](../mmap/struct.MmapRegion.html) `UffdRegion` lays out virtual memory
+/// in a contiguous block. See [`MmapRegion`](../mmap/struct.MmapRegion.html) for details of the
+/// memory layout.
+///
+/// The difference is that `UffdRegion` is lazy. Only the minimum required physical memory is set
+/// up to back that virtual memory before an `Instance` begins running. The stack and the heap
+/// are both lazily allocated at runtime.
+///
+/// That lazy allocation is handled by the [`userfaultfd`](http://man7.org/linux/man-pages/man2/userfaultfd.2.html)
+/// system in recent Linux kernels. The entire Region is registered with `userfaultfd` handle.
+/// When page faults occur due to attempts by the `Guest` to access the lazy memory, the `Guest`
+/// thread is paused and a message is sent over the `userfaultfd` handle.
+///
+/// That message is picked up a separate thread which has the job of handling page faults. How
+/// it is handled is dependent on where the page fault occurred. In the case where it occurs in
+/// the stack, we just zero out the page. In the case it occurs in the heap, it is handled
+/// differently depending on whether the page should contain data defined in the WebAssembly
+/// module. In the case it should be blank we again just zero it out. In the case that it should
+/// contain data, we copy the data into the page. In any case we finish by reawakening the `Guest`
+/// thread.
+///
+/// If the fault occurs in a guard page, we do nothing, and reawaken the thread without allocating
+/// the backing physical memory. This ends up causing the `Guest` thread to throw a SIGBUS. Which
+/// is caught and handled as normal.
pub struct UffdRegion {
uffd: Arc<Uffd>,
start: *mut c_void,
@@ -375,6 +401,14 @@ impl Drop for UffdRegion {
}
impl UffdRegion {
+ /// Create a new `UffdRegion` that can support a given number of instances, each subject to the
+ /// same runtime limits.
+ ///
+ /// The region is turned in an `Arc`, because any instances created from it carry a reference
+ /// back to the region.
+ ///
+ /// This also creates and starts a separate thread that is responsible for handling page faults
+ /// that occur within the memory region.
pub fn create(instance_capacity: usize, limits: &Limits) -> Result<Arc<Self>, Error> {
assert!(
limits.signal_stack_size % host_page_size() == 0,
