aboutsummaryrefslogtreecommitdiff
path: root/alacritty_terminal/src/tty/windows/child.rs
diff options
context:
space:
mode:
Diffstat (limited to 'alacritty_terminal/src/tty/windows/child.rs')
-rw-r--r--alacritty_terminal/src/tty/windows/child.rs65
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));
}