@@ -5,7 +5,9 @@ |
| 5 | 5 | use anyhow::Result; |
| 6 | 6 | use portable_pty::{native_pty_system, CommandBuilder, PtyPair, PtySize}; |
| 7 | 7 | use std::io::{Read, Write}; |
| 8 | +use std::sync::atomic::{AtomicBool, Ordering}; |
| 8 | 9 | use std::sync::mpsc::{self, Receiver, Sender}; |
| 10 | +use std::sync::Arc; |
| 9 | 11 | use std::thread; |
| 10 | 12 | |
| 11 | 13 | /// Manages a PTY connection to a shell process |
@@ -14,6 +16,8 @@ pub struct Pty { |
| 14 | 16 | writer: Box<dyn Write + Send>, |
| 15 | 17 | output_rx: Receiver<Vec<u8>>, |
| 16 | 18 | _output_thread: thread::JoinHandle<()>, |
| 19 | + /// Flag indicating the shell has exited |
| 20 | + shell_exited: Arc<AtomicBool>, |
| 17 | 21 | } |
| 18 | 22 | |
| 19 | 23 | impl Pty { |
@@ -50,17 +54,29 @@ impl Pty { |
| 50 | 54 | let mut reader = pair.master.try_clone_reader()?; |
| 51 | 55 | let (output_tx, output_rx): (Sender<Vec<u8>>, Receiver<Vec<u8>>) = mpsc::channel(); |
| 52 | 56 | |
| 57 | + // Flag to signal when shell exits |
| 58 | + let shell_exited = Arc::new(AtomicBool::new(false)); |
| 59 | + let shell_exited_clone = Arc::clone(&shell_exited); |
| 60 | + |
| 53 | 61 | let output_thread = thread::spawn(move || { |
| 54 | 62 | let mut buf = [0u8; 4096]; |
| 55 | 63 | loop { |
| 56 | 64 | match reader.read(&mut buf) { |
| 57 | | - Ok(0) => break, // EOF |
| 65 | + Ok(0) => { |
| 66 | + // EOF - shell exited |
| 67 | + shell_exited_clone.store(true, Ordering::SeqCst); |
| 68 | + break; |
| 69 | + } |
| 58 | 70 | Ok(n) => { |
| 59 | 71 | if output_tx.send(buf[..n].to_vec()).is_err() { |
| 60 | 72 | break; // Receiver dropped |
| 61 | 73 | } |
| 62 | 74 | } |
| 63 | | - Err(_) => break, |
| 75 | + Err(_) => { |
| 76 | + // Error - likely shell exited |
| 77 | + shell_exited_clone.store(true, Ordering::SeqCst); |
| 78 | + break; |
| 79 | + } |
| 64 | 80 | } |
| 65 | 81 | } |
| 66 | 82 | }); |
@@ -70,6 +86,7 @@ impl Pty { |
| 70 | 86 | writer, |
| 71 | 87 | output_rx, |
| 72 | 88 | _output_thread: output_thread, |
| 89 | + shell_exited, |
| 73 | 90 | }) |
| 74 | 91 | } |
| 75 | 92 | |
@@ -104,4 +121,9 @@ impl Pty { |
| 104 | 121 | })?; |
| 105 | 122 | Ok(()) |
| 106 | 123 | } |
| 124 | + |
| 125 | + /// Check if the shell is still alive |
| 126 | + pub fn is_alive(&self) -> bool { |
| 127 | + !self.shell_exited.load(Ordering::SeqCst) |
| 128 | + } |
| 107 | 129 | } |