sausage-vfs: layers (host, memory, generated, mounts), process guards, wasi:filesystem adapter

Checkpoint. More tests and the review findings follow.
This commit is contained in:
2026-10-23 00:08:02 +01:00
parent 01712e745a
commit 0a479b5800
15 changed files with 1932 additions and 1 deletions
+51
View File
@@ -0,0 +1,51 @@
//! Tracks blocking operations until their system calls return, independent of cancellation.
use std::sync::{
Arc,
atomic::{AtomicUsize, Ordering},
};
use tokio::sync::Notify;
#[derive(Default)]
struct State {
count: AtomicUsize,
idle: Notify,
}
/// A per-process operation tracker. Stop the process before awaiting idle.
#[derive(Clone, Default)]
pub struct Process(Arc<State>);
struct Guard(Arc<State>);
impl Drop for Guard {
fn drop(&mut self) {
if self.0.count.fetch_sub(1, Ordering::SeqCst) == 1 {
self.0.idle.notify_waiters();
}
}
}
impl Process {
/// Run a system call on the blocking pool. Cancellation does not release its guard.
pub async fn blocking<T: Send + 'static>(
&self,
operation: impl FnOnce() -> std::io::Result<T> + Send + 'static,
) -> std::io::Result<T> {
self.0.count.fetch_add(1, Ordering::SeqCst);
let guard = Guard(self.0.clone());
tokio::task::spawn_blocking(move || {
let _guard = guard;
operation()
})
.await
.map_err(std::io::Error::other)?
}
/// Wait for all outstanding system calls. The caller must prevent new operations.
pub async fn idle(&self) {
loop {
let notified = self.0.idle.notified();
tokio::pin!(notified);
notified.as_mut().enable();
if self.0.count.load(Ordering::SeqCst) == 0 {
return;
}
notified.await;
}
}
}