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:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user