summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJoe Wilm <joe@jwilm.com>2016-09-25 19:49:44 -0700
committerJoe Wilm <joe@jwilm.com>2016-09-25 19:49:44 -0700
commit3f6deb8e2ffa22403aca9fcf6b50bdccc75dc3cf (patch)
treedc8ea717e13921d6f66e2389b4b12bcb5e339e6a /src
parent6a5ac20defa558309a674e069f33febde1824c00 (diff)
downloadalacritty-3f6deb8e2ffa22403aca9fcf6b50bdccc75dc3cf.tar.gz
alacritty-3f6deb8e2ffa22403aca9fcf6b50bdccc75dc3cf.zip
Refactor EventLoop into event_loop module
This type and its implementations were seriously cluttering main.rs.
Diffstat (limited to 'src')
-rw-r--r--src/event_loop.rs231
-rw-r--r--src/input.rs5
-rw-r--r--src/main.rs241
-rw-r--r--src/util.rs3
4 files changed, 250 insertions, 230 deletions
diff --git a/src/event_loop.rs b/src/event_loop.rs
new file mode 100644
index 00000000..51eeccd1
--- /dev/null
+++ b/src/event_loop.rs
@@ -0,0 +1,231 @@
+//! The main event loop which performs I/O on the pseudoterminal
+use std::borrow::Cow;
+use std::io::{self, ErrorKind};
+use std::os::unix::io::AsRawFd;
+use std::sync::Arc;
+
+use mio::{self, Events, PollOpt, Ready};
+use mio::unix::EventedFd;
+
+use ansi;
+use term::Term;
+use util::thread;
+use sync::FairMutex;
+
+use super::Flag;
+
+pub struct EventLoop<Io> {
+ poll: mio::Poll,
+ pty: Io,
+ rx: mio::channel::Receiver<Msg>,
+ tx: mio::channel::Sender<Msg>,
+ terminal: Arc<FairMutex<Term>>,
+ proxy: ::glutin::WindowProxy,
+ signal_flag: Flag,
+}
+
+
+#[derive(Debug)]
+pub enum Msg {
+ Input(Cow<'static, [u8]>),
+}
+
+const CHANNEL: mio::Token = mio::Token(0);
+const PTY: mio::Token = mio::Token(1);
+
+impl<Io> EventLoop<Io>
+ where Io: io::Read + io::Write + Send + AsRawFd + 'static
+{
+ pub fn new(
+ terminal: Arc<FairMutex<Term>>,
+ proxy: ::glutin::WindowProxy,
+ signal_flag: Flag,
+ pty: Io,
+ ) -> EventLoop<Io> {
+ let (tx, rx) = ::mio::channel::channel();
+ EventLoop {
+ poll: mio::Poll::new().expect("create mio Poll"),
+ pty: pty,
+ tx: tx,
+ rx: rx,
+ terminal: terminal,
+ proxy: proxy,
+ signal_flag: signal_flag
+ }
+ }
+
+ pub fn channel(&self) -> mio::channel::Sender<Msg> {
+ self.tx.clone()
+ }
+
+ pub fn spawn(self) -> thread::JoinHandle<()> {
+
+ struct Writing {
+ source: Cow<'static, [u8]>,
+ written: usize,
+ }
+
+ impl Writing {
+ #[inline]
+ fn new(c: Cow<'static, [u8]>) -> Writing {
+ Writing { source: c, written: 0 }
+ }
+
+ #[inline]
+ fn advance(&mut self, n: usize) {
+ self.written += n;
+ }
+
+ #[inline]
+ fn remaining_bytes(&self) -> &[u8] {
+ &self.source[self.written..]
+ }
+
+ #[inline]
+ fn finished(&self) -> bool {
+ self.written >= self.source.len()
+ }
+ }
+
+ thread::spawn_named("pty reader", move || {
+
+ let EventLoop { poll, mut pty, rx, terminal, proxy, signal_flag, .. } = self;
+
+
+ let mut buf = [0u8; 4096];
+ let mut pty_parser = ansi::Processor::new();
+ let fd = pty.as_raw_fd();
+ let fd = EventedFd(&fd);
+
+ poll.register(&rx, CHANNEL, Ready::readable(), PollOpt::edge() | PollOpt::oneshot())
+ .unwrap();
+ poll.register(&fd, PTY, Ready::readable(), PollOpt::edge() | PollOpt::oneshot())
+ .unwrap();
+
+ let mut events = Events::with_capacity(1024);
+ let mut write_list = ::std::collections::VecDeque::new();
+ let mut writing = None;
+
+ 'event_loop: loop {
+ poll.poll(&mut events, None).expect("poll ok");
+
+ for event in events.iter() {
+ match event.token() {
+ CHANNEL => {
+ while let Ok(msg) = rx.try_recv() {
+ match msg {
+ Msg::Input(input) => {
+ write_list.push_back(input);
+ }
+ }
+ }
+
+ poll.reregister(
+ &rx, CHANNEL,
+ Ready::readable(),
+ PollOpt::edge() | PollOpt::oneshot()
+ ).expect("reregister channel");
+
+ if writing.is_some() || !write_list.is_empty() {
+ poll.reregister(
+ &fd,
+ PTY,
+ Ready::readable() | Ready::writable(),
+ PollOpt::edge() | PollOpt::oneshot()
+ ).expect("reregister fd after channel recv");
+ }
+ },
+ PTY => {
+ let kind = event.kind();
+
+ if kind.is_readable() {
+ loop {
+ match pty.read(&mut buf[..]) {
+ Ok(0) => break,
+ Ok(got) => {
+ let mut terminal = terminal.lock();
+ for byte in &buf[..got] {
+ pty_parser.advance(&mut *terminal, *byte);
+ }
+
+ terminal.dirty = true;
+
+ // Only wake up the event loop if it hasn't already been
+ // signaled. This is a really important optimization
+ // because waking up the event loop redundantly burns *a
+ // lot* of cycles.
+ if !signal_flag.get() {
+ proxy.wakeup_event_loop();
+ signal_flag.set(true);
+ }
+ },
+ Err(err) => {
+ match err.kind() {
+ ErrorKind::WouldBlock => break,
+ _ => panic!("unexpected read err: {:?}", err),
+ }
+ }
+ }
+ }
+ }
+
+ if kind.is_writable() {
+ if writing.is_none() {
+ writing = write_list
+ .pop_front()
+ .map(|c| Writing::new(c));
+ }
+
+ 'write_list_loop: while let Some(mut write_now) = writing.take() {
+ loop {
+ match pty.write(write_now.remaining_bytes()) {
+ Ok(0) => {
+ writing = Some(write_now);
+ break 'write_list_loop;
+ },
+ Ok(n) => {
+ write_now.advance(n);
+ if write_now.finished() {
+ writing = write_list
+ .pop_front()
+ .map(|next| Writing::new(next));
+
+ break;
+ } else {
+ }
+ },
+ Err(err) => {
+ writing = Some(write_now);
+ match err.kind() {
+ ErrorKind::WouldBlock => break 'write_list_loop,
+ // TODO
+ _ => panic!("unexpected err: {:?}", err),
+ }
+ }
+ }
+
+ }
+ }
+ }
+
+ if kind.is_hup() {
+ break 'event_loop;
+ }
+
+ let mut interest = Ready::readable();
+ if writing.is_some() || !write_list.is_empty() {
+ interest.insert(Ready::writable());
+ }
+
+ poll.reregister(&fd, PTY, interest, PollOpt::edge() | PollOpt::oneshot())
+ .expect("register fd after read/write");
+ },
+ _ => (),
+ }
+ }
+ }
+
+ println!("pty reader stopped");
+ })
+ }
+}
diff --git a/src/input.rs b/src/input.rs
index b2263d6e..0251b5f8 100644
--- a/src/input.rs
+++ b/src/input.rs
@@ -29,6 +29,7 @@ use glutin::{ElementState, VirtualKeyCode};
use glutin::{Mods, mods};
use term::mode::{self, TermMode};
+use event_loop;
/// Processes input from glutin.
///
@@ -47,14 +48,14 @@ pub trait Notify {
fn notify<B: Into<Cow<'static, [u8]>>>(&mut self, B);
}
-pub struct LoopNotifier(pub ::mio::channel::Sender<::EventLoopMessage>);
+pub struct LoopNotifier(pub ::mio::channel::Sender<event_loop::Msg>);
impl Notify for LoopNotifier {
fn notify<B>(&mut self, bytes: B)
where B: Into<Cow<'static, [u8]>>
{
let bytes = bytes.into();
- match self.0.send(::EventLoopMessage::Input(bytes)) {
+ match self.0.send(event_loop::Msg::Input(bytes)) {
Ok(_) => (),
Err(_) => panic!("expected send event loop msg"),
}
diff --git a/src/main.rs b/src/main.rs
index 4c740ad2..5a57b362 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -41,38 +41,39 @@ extern crate bitflags;
#[macro_use]
mod macros;
-mod renderer;
-pub mod grid;
-mod meter;
-pub mod config;
-mod input;
-mod index;
mod event;
-mod tty;
-pub mod ansi;
+mod event_loop;
+mod index;
+mod input;
+mod meter;
+mod renderer;
+mod sync;
mod term;
+mod tty;
mod util;
-mod sync;
+pub mod ansi;
+pub mod config;
+pub mod grid;
use std::sync::{mpsc, Arc};
-use std::fs::File;
use std::sync::atomic::{AtomicBool, Ordering};
use parking_lot::{MutexGuard};
+use event_loop::EventLoop;
+
use config::Config;
use meter::Meter;
use renderer::{QuadRenderer, GlyphCache};
use sync::FairMutex;
use term::Term;
use tty::process_should_exit;
-use util::thread;
/// Channel used by resize handling on mac
static mut resize_sender: Option<mpsc::Sender<(u32, u32)>> = None;
#[derive(Clone)]
-struct Flag(Arc<AtomicBool>);
+pub struct Flag(Arc<AtomicBool>);
impl Flag {
pub fn new(initial_value: bool) -> Flag {
Flag(Arc::new(AtomicBool::new(initial_value)))
@@ -235,223 +236,7 @@ fn main() {
println!("Goodbye");
}
-struct EventLoop {
- poll: mio::Poll,
- pty: File,
- rx: mio::channel::Receiver<EventLoopMessage>,
- tx: mio::channel::Sender<EventLoopMessage>,
- terminal: Arc<FairMutex<Term>>,
- proxy: ::glutin::WindowProxy,
- signal_flag: Flag,
-}
-
-const CHANNEL: mio::Token = mio::Token(0);
-const PTY: mio::Token = mio::Token(1);
-
-#[derive(Debug)]
-pub enum EventLoopMessage {
- Input(::std::borrow::Cow<'static, [u8]>),
-}
-impl EventLoop {
- pub fn new(
- terminal: Arc<FairMutex<Term>>,
- proxy: ::glutin::WindowProxy,
- signal_flag: Flag,
- pty: File,
- ) -> EventLoop {
- let (tx, rx) = ::mio::channel::channel();
- EventLoop {
- poll: mio::Poll::new().expect("create mio Poll"),
- pty: pty,
- tx: tx,
- rx: rx,
- terminal: terminal,
- proxy: proxy,
- signal_flag: signal_flag
- }
- }
-
- pub fn channel(&self) -> mio::channel::Sender<EventLoopMessage> {
- self.tx.clone()
- }
-
- pub fn spawn(self) -> std::thread::JoinHandle<()> {
- use mio::{Events, PollOpt, Ready};
- use mio::unix::EventedFd;
- use std::borrow::Cow;
- use std::os::unix::io::AsRawFd;
- use std::io::{Read, Write, ErrorKind};
-
- struct Writing {
- source: Cow<'static, [u8]>,
- written: usize,
- }
-
- impl Writing {
- #[inline]
- fn new(c: Cow<'static, [u8]>) -> Writing {
- Writing { source: c, written: 0 }
- }
-
- #[inline]
- fn advance(&mut self, n: usize) {
- self.written += n;
- }
-
- #[inline]
- fn remaining_bytes(&self) -> &[u8] {
- &self.source[self.written..]
- }
-
- #[inline]
- fn finished(&self) -> bool {
- self.written >= self.source.len()
- }
- }
-
- thread::spawn_named("pty reader", move || {
-
- let EventLoop { poll, mut pty, rx, terminal, proxy, signal_flag, .. } = self;
-
-
- let mut buf = [0u8; 4096];
- let mut pty_parser = ansi::Processor::new();
- let fd = pty.as_raw_fd();
- let fd = EventedFd(&fd);
-
- poll.register(&rx, CHANNEL, Ready::readable(), PollOpt::edge() | PollOpt::oneshot())
- .unwrap();
- poll.register(&fd, PTY, Ready::readable(), PollOpt::edge() | PollOpt::oneshot())
- .unwrap();
-
- let mut events = Events::with_capacity(1024);
- let mut write_list = ::std::collections::VecDeque::new();
- let mut writing = None;
-
- 'event_loop: loop {
- poll.poll(&mut events, None).expect("poll ok");
-
- for event in events.iter() {
- match event.token() {
- CHANNEL => {
- while let Ok(msg) = rx.try_recv() {
- match msg {
- EventLoopMessage::Input(input) => {
- write_list.push_back(input);
- }
- }
- }
-
- poll.reregister(
- &rx, CHANNEL,
- Ready::readable(),
- PollOpt::edge() | PollOpt::oneshot()
- ).expect("reregister channel");
-
- if writing.is_some() || !write_list.is_empty() {
- poll.reregister(
- &fd,
- PTY,
- Ready::readable() | Ready::writable(),
- PollOpt::edge() | PollOpt::oneshot()
- ).expect("reregister fd after channel recv");
- }
- },
- PTY => {
- let kind = event.kind();
-
- if kind.is_readable() {
- loop {
- match pty.read(&mut buf[..]) {
- Ok(0) => break,
- Ok(got) => {
- let mut terminal = terminal.lock();
- for byte in &buf[..got] {
- pty_parser.advance(&mut *terminal, *byte);
- }
-
- terminal.dirty = true;
-
- // Only wake up the event loop if it hasn't already been
- // signaled. This is a really important optimization
- // because waking up the event loop redundantly burns *a
- // lot* of cycles.
- if !signal_flag.get() {
- proxy.wakeup_event_loop();
- signal_flag.set(true);
- }
- },
- Err(err) => {
- match err.kind() {
- ErrorKind::WouldBlock => break,
- _ => panic!("unexpected read err: {:?}", err),
- }
- }
- }
- }
- }
-
- if kind.is_writable() {
- if writing.is_none() {
- writing = write_list
- .pop_front()
- .map(|c| Writing::new(c));
- }
-
- 'write_list_loop: while let Some(mut write_now) = writing.take() {
- loop {
- match pty.write(write_now.remaining_bytes()) {
- Ok(0) => {
- writing = Some(write_now);
- break 'write_list_loop;
- },
- Ok(n) => {
- write_now.advance(n);
- if write_now.finished() {
- writing = write_list
- .pop_front()
- .map(|next| Writing::new(next));
-
- break;
- } else {
- }
- },
- Err(err) => {
- writing = Some(write_now);
- match err.kind() {
- ErrorKind::WouldBlock => break 'write_list_loop,
- // TODO
- _ => panic!("unexpected err: {:?}", err),
- }
- }
- }
-
- }
- }
- }
-
- if kind.is_hup() {
- break 'event_loop;
- }
-
- let mut interest = Ready::readable();
- if writing.is_some() || !write_list.is_empty() {
- interest.insert(Ready::writable());
- }
-
- poll.reregister(&fd, PTY, interest, PollOpt::edge() | PollOpt::oneshot())
- .expect("register fd after read/write");
- },
- _ => (),
- }
- }
- }
-
- println!("pty reader stopped");
- })
- }
-}
struct Display {
window: Arc<glutin::Window>,
diff --git a/src/util.rs b/src/util.rs
index 693e26a8..69715d8e 100644
--- a/src/util.rs
+++ b/src/util.rs
@@ -23,4 +23,7 @@ pub mod thread {
{
::std::thread::Builder::new().name(name.into()).spawn(f).expect("thread spawn works")
}
+
+ pub use ::std::thread::*;
}
+