diff options
Diffstat (limited to 'alacritty_terminal/src/tty/windows/child.rs')
-rw-r--r-- | alacritty_terminal/src/tty/windows/child.rs | 65 |
1 files changed, 42 insertions, 23 deletions
diff --git a/alacritty_terminal/src/tty/windows/child.rs b/alacritty_terminal/src/tty/windows/child.rs index 19c8a195..6bc9ed20 100644 --- a/alacritty_terminal/src/tty/windows/child.rs +++ b/alacritty_terminal/src/tty/windows/child.rs @@ -1,8 +1,10 @@ use std::ffi::c_void; use std::io::Error; use std::sync::atomic::{AtomicPtr, Ordering}; +use std::sync::{mpsc, Arc, Mutex}; -use mio_extras::channel::{channel, Receiver, Sender}; +use polling::os::iocp::{CompletionPacket, PollerIocpExt}; +use polling::{Event, Poller}; use windows_sys::Win32::Foundation::{BOOLEAN, HANDLE}; use windows_sys::Win32::System::Threading::{ @@ -12,27 +14,43 @@ use windows_sys::Win32::System::Threading::{ use crate::tty::ChildEvent; +struct Interest { + poller: Arc<Poller>, + event: Event, +} + +struct ChildExitSender { + sender: mpsc::Sender<ChildEvent>, + interest: Arc<Mutex<Option<Interest>>>, +} + /// WinAPI callback to run when child process exits. extern "system" fn child_exit_callback(ctx: *mut c_void, timed_out: BOOLEAN) { if timed_out != 0 { return; } - let event_tx: Box<_> = unsafe { Box::from_raw(ctx as *mut Sender<ChildEvent>) }; - let _ = event_tx.send(ChildEvent::Exited); + let event_tx: Box<_> = unsafe { Box::from_raw(ctx as *mut ChildExitSender) }; + let _ = event_tx.sender.send(ChildEvent::Exited); + let interest = event_tx.interest.lock().unwrap(); + if let Some(interest) = interest.as_ref() { + interest.poller.post(CompletionPacket::new(interest.event)).ok(); + } } pub struct ChildExitWatcher { wait_handle: AtomicPtr<c_void>, - event_rx: Receiver<ChildEvent>, + event_rx: mpsc::Receiver<ChildEvent>, + interest: Arc<Mutex<Option<Interest>>>, } impl ChildExitWatcher { pub fn new(child_handle: HANDLE) -> Result<ChildExitWatcher, Error> { - let (event_tx, event_rx) = channel::<ChildEvent>(); + let (event_tx, event_rx) = mpsc::channel(); let mut wait_handle: HANDLE = 0; - let sender_ref = Box::new(event_tx); + let interest = Arc::new(Mutex::new(None)); + let sender_ref = Box::new(ChildExitSender { sender: event_tx, interest: interest.clone() }); let success = unsafe { RegisterWaitForSingleObject( @@ -51,13 +69,22 @@ impl ChildExitWatcher { Ok(ChildExitWatcher { wait_handle: AtomicPtr::from(wait_handle as *mut c_void), event_rx, + interest, }) } } - pub fn event_rx(&self) -> &Receiver<ChildEvent> { + pub fn event_rx(&self) -> &mpsc::Receiver<ChildEvent> { &self.event_rx } + + pub fn register(&self, poller: &Arc<Poller>, event: Event) { + *self.interest.lock().unwrap() = Some(Interest { poller: poller.clone(), event }); + } + + pub fn deregister(&self) { + *self.interest.lock().unwrap() = None; + } } impl Drop for ChildExitWatcher { @@ -72,36 +99,28 @@ impl Drop for ChildExitWatcher { mod tests { use std::os::windows::io::AsRawHandle; use std::process::Command; + use std::sync::Arc; use std::time::Duration; - use mio::{Events, Poll, PollOpt, Ready, Token}; - + use super::super::PTY_CHILD_EVENT_TOKEN; use super::*; #[test] pub fn event_is_emitted_when_child_exits() { const WAIT_TIMEOUT: Duration = Duration::from_millis(200); + let poller = Arc::new(Poller::new().unwrap()); + let mut child = Command::new("cmd.exe").spawn().unwrap(); let child_exit_watcher = ChildExitWatcher::new(child.as_raw_handle() as HANDLE).unwrap(); - - let mut events = Events::with_capacity(1); - let poll = Poll::new().unwrap(); - let child_events_token = Token::from(0usize); - - poll.register( - child_exit_watcher.event_rx(), - child_events_token, - Ready::readable(), - PollOpt::oneshot(), - ) - .unwrap(); + child_exit_watcher.register(&poller, Event::readable(PTY_CHILD_EVENT_TOKEN)); child.kill().unwrap(); // Poll for the event or fail with timeout if nothing has been sent. - poll.poll(&mut events, Some(WAIT_TIMEOUT)).unwrap(); - assert_eq!(events.iter().next().unwrap().token(), child_events_token); + let mut events = polling::Events::new(); + poller.wait(&mut events, Some(WAIT_TIMEOUT)).unwrap(); + assert_eq!(events.iter().next().unwrap().key, PTY_CHILD_EVENT_TOKEN); // Verify that at least one `ChildEvent::Exited` was received. assert_eq!(child_exit_watcher.event_rx().try_recv(), Ok(ChildEvent::Exited)); } |