aboutsummaryrefslogtreecommitdiff
path: root/src/platform
diff options
context:
space:
mode:
Diffstat (limited to 'src/platform')
-rw-r--r--src/platform/mod.rs2
-rw-r--r--src/platform/unix_common.rs44
-rw-r--r--src/platform/windows.rs19
3 files changed, 64 insertions, 1 deletions
diff --git a/src/platform/mod.rs b/src/platform/mod.rs
index d48ad4fa..335293e8 100644
--- a/src/platform/mod.rs
+++ b/src/platform/mod.rs
@@ -264,7 +264,7 @@ pub(crate) struct RemoteSshConfigPaths {
#[cfg(unix)]
mod unix_common;
#[cfg(unix)]
-pub(crate) use unix_common::{begin_cli_output, end_cli_output};
+pub(crate) use unix_common::{begin_cli_output, end_cli_output, RemoteBridgeWake};
mod client_state;
pub(crate) use client_state::{create_private_state_file, replace_file, sync_parent_directory};
diff --git a/src/platform/unix_common.rs b/src/platform/unix_common.rs
index 104f6b69..0df215d6 100644
--- a/src/platform/unix_common.rs
+++ b/src/platform/unix_common.rs
@@ -27,6 +27,50 @@ pub(crate) fn wait_client_stream_readable(stream: &crate::ipc::LocalStream) -> s
Ok(())
}
+pub(crate) struct RemoteBridgeWake {
+ reader: std::os::unix::net::UnixStream,
+ writer: std::os::unix::net::UnixStream,
+}
+
+impl RemoteBridgeWake {
+ pub(crate) fn new() -> std::io::Result<Self> {
+ let (reader, writer) = std::os::unix::net::UnixStream::pair()?;
+ Ok(Self { reader, writer })
+ }
+
+ pub(crate) fn cancel(&self) -> std::io::Result<()> {
+ // EOF stays readable, including when cancellation precedes the wait.
+ self.writer.shutdown(std::net::Shutdown::Write)
+ }
+
+ pub(crate) fn wait(&self, stream: &crate::ipc::LocalStream) -> std::io::Result<()> {
+ use std::os::fd::{AsFd as _, AsRawFd as _};
+ let crate::ipc::LocalStream::UdSocket(stream) = stream;
+ let mut descriptors = [
+ libc::pollfd {
+ fd: stream.as_fd().as_raw_fd(),
+ events: libc::POLLIN,
+ revents: 0,
+ },
+ libc::pollfd {
+ fd: self.reader.as_raw_fd(),
+ events: libc::POLLIN,
+ revents: 0,
+ },
+ ];
+ loop {
+ // SAFETY: both descriptors remain borrowed and the array has two entries.
+ if unsafe { libc::poll(descriptors.as_mut_ptr(), 2, -1) } >= 0 {
+ return Ok(());
+ }
+ let error = std::io::Error::last_os_error();
+ if error.kind() != std::io::ErrorKind::Interrupted {
+ return Err(error);
+ }
+ }
+ }
+}
+
pub(super) fn read_terminal_grid_size() -> std::io::Result<(u16, u16)> {
crossterm::terminal::window_size().map(|size| (size.columns, size.rows))
}
diff --git a/src/platform/windows.rs b/src/platform/windows.rs
index 4deb1864..e58bacae 100644
--- a/src/platform/windows.rs
+++ b/src/platform/windows.rs
@@ -24,6 +24,25 @@ pub(crate) fn classify_child_exit(status: &portable_pty::ExitStatus) -> super::C
}
}
+pub(crate) struct RemoteBridgeWake;
+
+impl RemoteBridgeWake {
+ pub(crate) fn new() -> std::io::Result<Self> {
+ Ok(Self)
+ }
+
+ pub(crate) fn cancel(&self) -> std::io::Result<()> {
+ // The named-pipe reader checks its cancellation flag between peeks.
+ Ok(())
+ }
+
+ pub(crate) fn wait(&self, _stream: &crate::ipc::LocalStream) -> std::io::Result<()> {
+ // Synchronous named pipes still use peek-before-read polling on Windows.
+ std::thread::sleep(Duration::from_millis(1));
+ Ok(())
+ }
+}
+
pub(crate) fn wait_client_stream_readable(
_stream: &crate::ipc::LocalStream,
) -> std::io::Result<()> {