diff options
Diffstat (limited to 'src/platform')
| -rw-r--r-- | src/platform/mod.rs | 49 | ||||
| -rw-r--r-- | src/platform/unix_common.rs | 8 | ||||
| -rw-r--r-- | src/platform/windows.rs | 9 |
3 files changed, 66 insertions, 0 deletions
diff --git a/src/platform/mod.rs b/src/platform/mod.rs index 86a431aa..d48ad4fa 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -25,6 +25,36 @@ pub enum Signal { Kill, } +/// Why a pane runtime ended, before application persistence policy is applied. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ChildExitReason { + Exited, + Interrupted, + /// Imported runtimes have no child wait handle in the replacement server. + #[cfg(unix)] + Handoff, + WaitFailed, +} + +impl ChildExitReason { + pub(crate) fn requires_session_checkpoint(self) -> bool { + match self { + Self::Interrupted => true, + #[cfg(unix)] + Self::Handoff => true, + _ => false, + } + } +} + +#[cfg(unix)] +pub(crate) use unix_common::classify_child_exit; + +#[cfg(not(any(unix, windows)))] +pub(crate) fn classify_child_exit(_status: &portable_pty::ExitStatus) -> ChildExitReason { + ChildExitReason::Exited +} + pub(crate) fn detached_custom_command_process(command: &str) -> std::process::Command { let mut process = detached_custom_command_process_platform(command); configure_background_command(&mut process); @@ -415,6 +445,25 @@ impl PrefixInputSource for RealPrefixInputSource { } } +#[cfg(all(test, any(unix, windows)))] +#[test] +fn child_exit_classification_only_checkpoints_interruptions() { + for code in [0, 1, 130, 255, 0xC0000005] { + let reason = classify_child_exit(&portable_pty::ExitStatus::with_exit_code(code)); + assert_eq!(reason, ChildExitReason::Exited, "exit code {code:#x}"); + assert!(!reason.requires_session_checkpoint()); + } + #[cfg(windows)] + let status = portable_pty::ExitStatus::with_exit_code(0xC000013A); + #[cfg(not(windows))] + let status = portable_pty::ExitStatus::with_signal("Terminated: 15"); + assert_eq!(classify_child_exit(&status), ChildExitReason::Interrupted); + assert!(classify_child_exit(&status).requires_session_checkpoint()); + #[cfg(unix)] + assert!(ChildExitReason::Handoff.requires_session_checkpoint()); + assert!(!ChildExitReason::WaitFailed.requires_session_checkpoint()); +} + #[cfg(all(test, unix))] mod tests { use super::*; diff --git a/src/platform/unix_common.rs b/src/platform/unix_common.rs index dff67357..104f6b69 100644 --- a/src/platform/unix_common.rs +++ b/src/platform/unix_common.rs @@ -1,5 +1,13 @@ use std::path::{Path, PathBuf}; +pub(crate) fn classify_child_exit(status: &portable_pty::ExitStatus) -> super::ChildExitReason { + if status.signal().is_some() { + super::ChildExitReason::Interrupted + } else { + super::ChildExitReason::Exited + } +} + pub(crate) fn wait_client_stream_readable(stream: &crate::ipc::LocalStream) -> std::io::Result<()> { use std::os::fd::{AsFd as _, AsRawFd as _}; let crate::ipc::LocalStream::UdSocket(stream) = stream; diff --git a/src/platform/windows.rs b/src/platform/windows.rs index ce0afedb..4deb1864 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -15,6 +15,15 @@ use std::{ mod clipboard_image; +pub(crate) fn classify_child_exit(status: &portable_pty::ExitStatus) -> super::ChildExitReason { + // STATUS_CONTROL_C_EXIT is reported without a Unix signal by portable-pty. + if status.exit_code() == 0xC000013A { + super::ChildExitReason::Interrupted + } else { + super::ChildExitReason::Exited + } +} + pub(crate) fn wait_client_stream_readable( _stream: &crate::ipc::LocalStream, ) -> std::io::Result<()> { |
