Keep file-watch observation from serializing unrelated IO
Scope open-registration and rename/remove ordering to overlapping paths; let descriptor mutations and directory creation proceed without that lock. Prove blocked opens/writes cannot stall unrelated namespaces, including a queued rename, and retain post-rename descriptor notifications. Document handler-owned watch lifetimes and narrow paths; test natural idle exit. Card: SAU-359
This commit is contained in:
@@ -63,6 +63,41 @@ impl Probe {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Poll the watch in the handler, then return idle without a background task.
|
||||
async fn watch_once(&self, p: WatchPath) -> Result<()> {
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
rc::Rc,
|
||||
task::{Poll, Waker},
|
||||
};
|
||||
let state = Rc::new(RefCell::new((false, None::<Waker>)));
|
||||
let received = state.clone();
|
||||
let mut watch = std::pin::pin!(std::future::IntoFuture::into_future(
|
||||
call("core.watch", json!({"path":p.path})).on_notify(move |name, _| {
|
||||
if name == "armed" {
|
||||
let mut state = received.borrow_mut();
|
||||
state.0 = true;
|
||||
if let Some(waker) = state.1.take() {
|
||||
waker.wake();
|
||||
}
|
||||
}
|
||||
})
|
||||
));
|
||||
std::future::poll_fn(|cx| {
|
||||
if let Poll::Ready(result) = watch.as_mut().poll(cx) {
|
||||
return Poll::Ready(result.map(|_| ()));
|
||||
}
|
||||
let mut state = state.borrow_mut();
|
||||
state.1 = Some(cx.waker().clone());
|
||||
if state.0 {
|
||||
Poll::Ready(Ok(()))
|
||||
} else {
|
||||
Poll::Pending
|
||||
}
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
/// Publish a control endpoint until EOF.
|
||||
async fn serve(&self) -> Result<()> {
|
||||
sausage_plugin::listen("/endpoint", std::rc::Rc::new(Control)).await
|
||||
|
||||
@@ -108,6 +108,15 @@ fn protocol() {
|
||||
}
|
||||
p.finishes();
|
||||
}
|
||||
// A handler-owned watch does not keep an idle process alive after return,
|
||||
// even though the host never answers the watch and stdin remains open.
|
||||
let mut p = start(&wasm, &dir);
|
||||
p.request("watch_once", json!({"path":"/mailbox"}));
|
||||
let watch = p.read();
|
||||
assert_eq!(watch["method"], "core.watch");
|
||||
p.send(json!({"jsonrpc":"2.0","method":"core.notify","params":{"call":watch["id"],"name":"armed","params":{}}}));
|
||||
assert_eq!(p.read()["result"], Value::Null);
|
||||
p.finishes();
|
||||
let mut p = start(&wasm, &dir);
|
||||
p.request("rpc.discover", json!({}));
|
||||
let d = p.read();
|
||||
|
||||
Reference in New Issue
Block a user