Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/process-daemon/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ that wakes partial requests and blocked subscription writes before joining.
On Unix the daemon loop sleeps in `poll(2)` on the listener and a private wake
socket pair until a connection arrives, a stop or ownership change wakes it, an
ownership deadline is due, or a two-second safety net elapses. Windows still
polls every 10 ms.
polls every 25 ms.

The Windows named-pipe backend keeps protocol 7 and the registration fields
`instance_id`, `pid`, `protocol`, `socket`, and `token`. Treat `socket` as an opaque
Expand Down Expand Up @@ -332,7 +332,7 @@ coverage on their own.
On Windows, normal root-child exit hands the ConPTY master to the existing
child-wait worker for closing. The actor and reader continue draining until the
real output-pipe EOF; only then is the final exit event published. The worker
checks the root's wait handle at 10 ms intervals. After the master is handed
checks the root's wait handle at 25 ms intervals. After the master is handed
off, Windows input and resize requests fail with a child-exited error; final
snapshots, rows, and replay remain readable until the terminal is removed.
Unix post-exit PTY operations retain their existing behavior.
Expand Down
6 changes: 4 additions & 2 deletions packages/process-daemon/src/service/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ use windows_sys::Win32::{

use super::ActorMessage;

const EXIT_POLL_INTERVAL: Duration = Duration::from_millis(25);

/// Keep blocking ClosePseudoConsole off the actor/reader without introducing
/// another worker. The actor hands its unique master here on root exit or on
/// teardown; closing it then produces the real output-pipe EOF.
/// Root-exit detection uses a 10 ms poll interval. After reaping, the
/// Root-exit detection uses a 25 ms poll interval. After reaping, the
/// worker blocks on the close channel rather than continuing to poll.
pub(super) fn wait_and_close(
mut child: Box<dyn Child + Send + Sync>,
Expand All @@ -37,7 +39,7 @@ pub(super) fn wait_and_close(
let request = if reported {
close.recv().map_err(|_| RecvTimeoutError::Disconnected)
} else {
close.recv_timeout(Duration::from_millis(10))
close.recv_timeout(EXIT_POLL_INTERVAL)
};
match request {
Ok(master) => {
Expand Down
2 changes: 1 addition & 1 deletion packages/process-daemon/src/transport/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
//! frame before the peer has had a chance to read it.
//!
//! The daemon blocks in `Listener::wait` (Unix: poll(2) on the listener and a
//! `Wake` socket pair; Windows: still a 10 ms poll) and then calls `accept` until
//! `Wake` socket pair; Windows: still a 25 ms poll) and then calls `accept` until
//! it returns `None`. Connection reads/writes run only on its handler threads. A
//! separate `Cancellation` can wake both directions without waiting for either
//! handler or peer. `finish_response` and a disconnect monitor's `finish` are
Expand Down
8 changes: 5 additions & 3 deletions packages/process-daemon/src/transport/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ use security::PrivateSecurity;
const BUFFER_BYTES: u32 = 64 * 1024;
const CONNECT_TIMEOUT: Duration = Duration::from_secs(5);
const COMPLETION_TIMEOUT: Duration = Duration::from_secs(2);
/// Interim idle poll until `wait` blocks on the pending connect and a stop event.
const POLL_INTERVAL: Duration = Duration::from_millis(25);

pub(crate) struct Listener {
endpoint: Vec<u16>,
Expand Down Expand Up @@ -83,9 +85,9 @@ impl Listener {
self.pending.operation.pipe.cancel();
}

/// Windows keeps the 10 ms poll for now; the caller then polls `accept`.
/// Windows keeps a 25 ms poll for now; the caller then polls `accept`.
pub fn wait(&self, _wake: &Wake, listen: bool, timeout: Duration) -> io::Result<Readiness> {
thread::sleep(timeout.min(Duration::from_millis(10)));
thread::sleep(timeout.min(POLL_INTERVAL));
// `timed_out` stays false: Windows cannot tell, and the missed-wake detector must stay off.
Ok(Readiness {
connection: listen,
Expand All @@ -102,7 +104,7 @@ pub(crate) struct Readiness {
pub timed_out: bool,
}

/// Windows keeps the 10 ms poll for now, so notify is a no-op.
/// Windows keeps a 25 ms poll for now, so notify is a no-op.
pub(crate) struct Wake;

impl Wake {
Expand Down
Loading