1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-28 07:55:03 +03:00

simplify child waiting

This commit is contained in:
Wez Furlong 2018-02-22 00:35:51 -08:00
parent c9c5b25b01
commit ac7d2a9cda
3 changed files with 21 additions and 132 deletions

View File

@ -433,6 +433,8 @@ impl TerminalWindow {
}
Err(TryRecvError::Disconnected) => bail!("clipboard thread died"),
}
self.test_for_child_exit()?;
}
_ => {}
}

View File

@ -81,10 +81,8 @@ fn run_glium(
let poll = Poll::new()?;
poll.register(&master, Token(0), Ready::readable(), PollOpt::edge())?;
let waiter = sigchld::ChildWaiter::new()?;
poll.register(&waiter, Token(2), Ready::readable(), PollOpt::edge())?;
let mut events_loop = glium::glutin::EventsLoop::new();
sigchld::activate(events_loop.create_proxy())?;
let mut window = gliumwindows::TerminalWindow::new(
&events_loop,
@ -113,12 +111,6 @@ fn run_glium(
if event.token() == Token(0) && event.readiness().is_readable() {
window.handle_pty_readable_event()?;
}
if event.token() == Token(2) {
println!("sigchld ready");
let pid = waiter.read_one()?;
println!("got sigchld from pid {}", pid);
window.test_for_child_exit()?;
}
}
} else if window.need_paint() {
window.paint()?;

View File

@ -1,142 +1,37 @@
//! Helper for detecting SIGCHLD
use failure::Error;
use glium::glutin::EventsLoopProxy;
use libc;
use mio::{Poll, PollOpt, Ready, Token};
use mio::event::Evented;
use mio::unix::EventedFd;
use std::io;
use std::mem;
use std::os::unix::io::RawFd;
use std::ptr;
#[cfg(not(target_os = "linux"))]
static mut WRITE_END: RawFd = -1;
static mut EVENT_LOOP: Option<EventsLoopProxy> = None;
pub struct ChildWaiter {
fd: RawFd,
}
impl Drop for ChildWaiter {
fn drop(&mut self) {
unsafe {
libc::close(self.fd);
}
}
}
#[cfg(not(target_os = "linux"))]
extern "C" fn chld_handler(_signo: libc::c_int, si: *const libc::siginfo_t, _: *const u8) {
extern "C" fn chld_handler(_signo: libc::c_int, _si: *const libc::siginfo_t, _: *const u8) {
unsafe {
let pid = (*si).si_pid;
libc::write(
WRITE_END,
&pid as *const _ as *const libc::c_void,
mem::size_of::<libc::pid_t>(),
);
}
}
impl ChildWaiter {
#[cfg(not(target_os = "linux"))]
pub fn new() -> Result<ChildWaiter, Error> {
unsafe {
let mut pipe: [RawFd; 2] = [-1, -1];
let res = libc::pipe(pipe.as_mut_ptr());
if res == -1 {
bail!("pipe failed: {:?}", io::Error::last_os_error());
match EVENT_LOOP.as_mut() {
Some(proxy) => {
proxy.wakeup().ok();
}
WRITE_END = pipe[1];
let mut sa: libc::sigaction = mem::zeroed();
sa.sa_sigaction = chld_handler as usize;
sa.sa_flags = (libc::SA_SIGINFO | libc::SA_RESTART | libc::SA_NOCLDSTOP) as _;
let res = libc::sigaction(libc::SIGCHLD, &sa, ptr::null_mut());
if res == -1 {
bail!("sigaction SIGCHLD failed: {:?}", io::Error::last_os_error());
}
Ok(Self { fd: pipe[0] })
}
}
#[cfg(target_os = "linux")]
pub fn new() -> Result<ChildWaiter, Error> {
unsafe {
let mut mask: libc::sigset_t = mem::zeroed();
libc::sigaddset(&mut mask, libc::SIGCHLD);
let res = libc::sigprocmask(libc::SIG_BLOCK, &mut mask, ptr::null_mut());
if res == -1 {
bail!(
"sigprocmask BLOCK SIGCHLD failed: {:?}",
io::Error::last_os_error()
);
}
let fd = libc::signalfd(-1, &mask, libc::SFD_NONBLOCK | libc::SFD_CLOEXEC);
if fd == -1 {
bail!("signalfd SIGCHLD failed: {:?}", io::Error::last_os_error());
}
Ok(ChildWaiter { fd })
}
}
#[cfg(not(target_os = "linux"))]
pub fn read_one(&self) -> Result<u32, Error> {
let mut pid: libc::pid_t = 0;
let res = unsafe {
libc::read(
self.fd,
&mut pid as *mut _ as *mut libc::c_void,
mem::size_of::<libc::pid_t>(),
)
};
if res == mem::size_of::<libc::pid_t>() as isize {
Ok(pid as u32)
} else {
bail!("signalfd read failed: {:?}", io::Error::last_os_error());
}
}
#[cfg(target_os = "linux")]
pub fn read_one(&self) -> Result<u32, Error> {
const BUFSIZE: usize = mem::size_of::<libc::signalfd_siginfo>();
let mut buf = [0u8; BUFSIZE];
let res = unsafe { libc::read(self.fd, buf.as_mut_ptr() as *mut _, buf.len()) };
if res == BUFSIZE as isize {
let siginfo: libc::signalfd_siginfo = unsafe { mem::transmute(buf) };
Ok(siginfo.ssi_pid)
} else {
bail!("signalfd read failed: {:?}", io::Error::last_os_error());
None => (),
}
}
}
/// Glue for working with mio
impl Evented for ChildWaiter {
fn register(
&self,
poll: &Poll,
token: Token,
interest: Ready,
opts: PollOpt,
) -> io::Result<()> {
EventedFd(&self.fd).register(poll, token, interest, opts)
}
pub fn activate(proxy: EventsLoopProxy) -> Result<(), Error> {
unsafe {
EVENT_LOOP = Some(proxy);
fn reregister(
&self,
poll: &Poll,
token: Token,
interest: Ready,
opts: PollOpt,
) -> io::Result<()> {
EventedFd(&self.fd).reregister(poll, token, interest, opts)
}
let mut sa: libc::sigaction = mem::zeroed();
sa.sa_sigaction = chld_handler as usize;
sa.sa_flags = (libc::SA_SIGINFO | libc::SA_RESTART | libc::SA_NOCLDSTOP) as _;
let res = libc::sigaction(libc::SIGCHLD, &sa, ptr::null_mut());
if res == -1 {
bail!("sigaction SIGCHLD failed: {:?}", io::Error::last_os_error());
}
fn deregister(&self, poll: &Poll) -> io::Result<()> {
EventedFd(&self.fd).deregister(poll)
Ok(())
}
}