1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-23 13:21:38 +03:00

poll the client tab asynchronously

Restructure the poll routine so that we don't block the gui thread
while we wait for the render data to be returned from the server.
This commit is contained in:
Wez Furlong 2019-06-14 20:30:45 -07:00
parent 036ff424f0
commit 99d6c12532
3 changed files with 54 additions and 11 deletions

View File

@ -199,6 +199,16 @@ impl<T: Send + 'static> Future<T> {
}
}
pub fn is_ready(&self) -> bool {
match &self.state {
FutureState::Waiting(core) => {
let locked = core.data.lock().unwrap();
locked.result.is_some()
}
FutureState::Ready(_) => true,
}
}
/// When this future resolves, then map the result via the
/// supplied lambda, which returns something that is convertible
/// to a Future.

View File

@ -63,8 +63,23 @@ fn client_thread_inner(
) -> Fallible<()> {
let mut next_serial = 0u64;
loop {
match rx.try_recv() {
Ok(msg) => match msg {
let msg = if promises.is_empty() {
// If we don't have any results to read back, then we can and
// should block on an incoming request, otherwise we'll busy
// wait in this loop
match rx.recv() {
Ok(msg) => Some(msg),
Err(err) => bail!("Client was destroyed: {}", err),
}
} else {
match rx.try_recv() {
Ok(msg) => Some(msg),
Err(TryRecvError::Empty) => None,
Err(TryRecvError::Disconnected) => bail!("Client was destroyed"),
}
};
if let Some(msg) = msg {
match msg {
ReaderMessage::SendPdu { pdu, promise } => {
let serial = next_serial;
next_serial += 1;
@ -73,9 +88,7 @@ fn client_thread_inner(
pdu.encode(&mut stream, serial)?;
stream.flush()?;
}
},
Err(TryRecvError::Empty) => {}
Err(TryRecvError::Disconnected) => bail!("Client was destroyed"),
}
}
if !promises.is_empty() {

View File

@ -7,6 +7,7 @@ use failure::Fallible;
use filedescriptor::Pipe;
use log::error;
use portable_pty::PtySize;
use promise::Future;
use std::cell::RefCell;
use std::cell::RefMut;
use std::ops::Range;
@ -41,6 +42,7 @@ impl ClientTab {
last_poll: RefCell::new(Instant::now()),
dirty_all: RefCell::new(true),
dead: RefCell::new(false),
poll_future: RefCell::new(None),
};
let reader = Pipe::new().expect("Pipe::new failed");
@ -157,12 +159,32 @@ struct RenderableState {
last_poll: RefCell<Instant>,
dirty_all: RefCell<bool>,
dead: RefCell<bool>,
poll_future: RefCell<Option<Future<GetCoarseTabRenderableDataResponse>>>,
}
const POLL_INTERVAL: Duration = Duration::from_millis(50);
impl RenderableState {
fn poll(&self) -> Fallible<()> {
let ready = self
.poll_future
.borrow()
.as_ref()
.map(Future::is_ready)
.unwrap_or(false);
if ready {
let coarse = self.poll_future.borrow_mut().take().unwrap().wait()?;
self.coarse.borrow_mut().replace(coarse);
log::trace!(
"poll: got coarse data in {:?}",
self.last_poll.borrow().elapsed()
);
*self.last_poll.borrow_mut() = Instant::now();
} else if self.poll_future.borrow().is_some() {
// We have a poll in progress
return Ok(());
}
let dirty_all = *self.dirty_all.borrow();
if !dirty_all {
@ -174,15 +196,13 @@ impl RenderableState {
{
let mut client = self.client.client.lock().unwrap();
let coarse = client
.get_coarse_tab_renderable_data(GetCoarseTabRenderableData {
*self.poll_future.borrow_mut() = Some(client.get_coarse_tab_renderable_data(
GetCoarseTabRenderableData {
tab_id: self.remote_tab_id,
dirty_all,
})
.wait()?;
self.coarse.borrow_mut().replace(coarse);
},
));
}
*self.last_poll.borrow_mut() = Instant::now();
*self.dirty_all.borrow_mut() = false;
Ok(())
}