mirror of
https://github.com/asciinema/asciinema.git
synced 2025-12-16 03:38:03 +01:00
Make SignalFd handle multiple signals with single pipe
This commit is contained in:
121
src/pty.rs
121
src/pty.rs
@@ -6,6 +6,7 @@ use std::io::{self, ErrorKind, Read, Write};
|
|||||||
use std::os::fd::AsFd;
|
use std::os::fd::AsFd;
|
||||||
use std::os::fd::{BorrowedFd, OwnedFd};
|
use std::os::fd::{BorrowedFd, OwnedFd};
|
||||||
use std::os::unix::io::AsRawFd;
|
use std::os::unix::io::AsRawFd;
|
||||||
|
use std::sync::Arc;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
use anyhow::bail;
|
use anyhow::bail;
|
||||||
@@ -100,13 +101,8 @@ fn copy<T: Tty, H: Handler>(
|
|||||||
let mut output: Vec<u8> = Vec::with_capacity(BUF_SIZE);
|
let mut output: Vec<u8> = Vec::with_capacity(BUF_SIZE);
|
||||||
let mut master_closed = false;
|
let mut master_closed = false;
|
||||||
|
|
||||||
let sigwinch_fd = SignalFd::open(SIGWINCH)?;
|
let mut signal_fd =
|
||||||
let sigint_fd = SignalFd::open(SIGINT)?;
|
SignalFd::open(&[SIGWINCH, SIGINT, SIGTERM, SIGQUIT, SIGHUP, SIGALRM, SIGCHLD])?;
|
||||||
let sigterm_fd = SignalFd::open(SIGTERM)?;
|
|
||||||
let sigquit_fd = SignalFd::open(SIGQUIT)?;
|
|
||||||
let sighup_fd = SignalFd::open(SIGHUP)?;
|
|
||||||
let sigalrm_fd = SignalFd::open(SIGALRM)?;
|
|
||||||
let sigchld_fd = SignalFd::open(SIGCHLD)?;
|
|
||||||
|
|
||||||
set_non_blocking(&master)?;
|
set_non_blocking(&master)?;
|
||||||
|
|
||||||
@@ -117,13 +113,7 @@ fn copy<T: Tty, H: Handler>(
|
|||||||
let mut wfds = FdSet::new();
|
let mut wfds = FdSet::new();
|
||||||
|
|
||||||
rfds.insert(tty_fd);
|
rfds.insert(tty_fd);
|
||||||
rfds.insert(sigwinch_fd.as_fd());
|
rfds.insert(signal_fd.as_fd());
|
||||||
rfds.insert(sigint_fd.as_fd());
|
|
||||||
rfds.insert(sigterm_fd.as_fd());
|
|
||||||
rfds.insert(sigquit_fd.as_fd());
|
|
||||||
rfds.insert(sighup_fd.as_fd());
|
|
||||||
rfds.insert(sigalrm_fd.as_fd());
|
|
||||||
rfds.insert(sigchld_fd.as_fd());
|
|
||||||
|
|
||||||
if !master_closed {
|
if !master_closed {
|
||||||
rfds.insert(master_fd);
|
rfds.insert(master_fd);
|
||||||
@@ -149,13 +139,7 @@ fn copy<T: Tty, H: Handler>(
|
|||||||
let master_write = wfds.contains(master_fd);
|
let master_write = wfds.contains(master_fd);
|
||||||
let tty_read = rfds.contains(tty_fd);
|
let tty_read = rfds.contains(tty_fd);
|
||||||
let tty_write = wfds.contains(tty_fd);
|
let tty_write = wfds.contains(tty_fd);
|
||||||
let sigwinch_read = rfds.contains(sigwinch_fd.as_fd());
|
let signal_read = rfds.contains(signal_fd.as_fd());
|
||||||
let sigint_read = rfds.contains(sigint_fd.as_fd());
|
|
||||||
let sigterm_read = rfds.contains(sigterm_fd.as_fd());
|
|
||||||
let sigquit_read = rfds.contains(sigquit_fd.as_fd());
|
|
||||||
let sighup_read = rfds.contains(sighup_fd.as_fd());
|
|
||||||
let sigalrm_read = rfds.contains(sigalrm_fd.as_fd());
|
|
||||||
let sigchld_read = rfds.contains(sigchld_fd.as_fd());
|
|
||||||
|
|
||||||
if master_read {
|
if master_read {
|
||||||
while let Some(n) = read_non_blocking(&mut master, &mut buf)? {
|
while let Some(n) = read_non_blocking(&mut master, &mut buf)? {
|
||||||
@@ -228,47 +212,32 @@ fn copy<T: Tty, H: Handler>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if sigwinch_read {
|
|
||||||
sigwinch_fd.flush();
|
|
||||||
let winsize = tty.get_size();
|
|
||||||
|
|
||||||
if handler.resize(epoch.elapsed(), winsize.into()) {
|
|
||||||
set_pty_size(master_raw_fd, &winsize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut kill_the_child = false;
|
let mut kill_the_child = false;
|
||||||
|
|
||||||
if sigint_read {
|
if signal_read {
|
||||||
sigint_fd.flush();
|
for signal in signal_fd.flush() {
|
||||||
kill_the_child = true;
|
match signal {
|
||||||
}
|
SIGWINCH => {
|
||||||
|
let winsize = tty.get_size();
|
||||||
|
|
||||||
if sigterm_read {
|
if handler.resize(epoch.elapsed(), winsize.into()) {
|
||||||
sigterm_fd.flush();
|
set_pty_size(master_raw_fd, &winsize);
|
||||||
kill_the_child = true;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if sigquit_read {
|
SIGINT | SIGTERM | SIGQUIT | SIGHUP => {
|
||||||
sigquit_fd.flush();
|
kill_the_child = true;
|
||||||
kill_the_child = true;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if sighup_read {
|
SIGCHLD => {
|
||||||
sighup_fd.flush();
|
if let Ok(status) = wait::waitpid(child, Some(WaitPidFlag::WNOHANG)) {
|
||||||
kill_the_child = true;
|
if status != WaitStatus::StillAlive {
|
||||||
}
|
return Ok(Some(status));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if sigalrm_read {
|
_ => {}
|
||||||
sigalrm_fd.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
if sigchld_read {
|
|
||||||
sigchld_fd.flush();
|
|
||||||
|
|
||||||
if let Ok(status) = wait::waitpid(child, Some(WaitPidFlag::WNOHANG)) {
|
|
||||||
if status != WaitStatus::StillAlive {
|
|
||||||
return Ok(Some(status));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -338,33 +307,51 @@ fn write_non_blocking<W: Write + ?Sized>(sink: &mut W, buf: &[u8]) -> io::Result
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct SignalFd {
|
struct SignalFd {
|
||||||
sigid: SigId,
|
sigids: Vec<SigId>,
|
||||||
rx: OwnedFd,
|
rx: OwnedFd,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SignalFd {
|
impl SignalFd {
|
||||||
fn open(signal: libc::c_int) -> anyhow::Result<Self> {
|
fn open(signals: &[libc::c_int]) -> anyhow::Result<Self> {
|
||||||
let (rx, tx) = unistd::pipe()?;
|
let (rx, tx) = unistd::pipe()?;
|
||||||
set_non_blocking(&rx)?;
|
set_non_blocking(&rx)?;
|
||||||
set_non_blocking(&tx)?;
|
set_non_blocking(&tx)?;
|
||||||
|
|
||||||
let sigid = unsafe {
|
let tx = Arc::new(tx);
|
||||||
signal_hook::low_level::register(signal, move || {
|
|
||||||
let _ = unistd::write(&tx, &[0]);
|
|
||||||
})
|
|
||||||
}?;
|
|
||||||
|
|
||||||
Ok(Self { sigid, rx })
|
let mut sigids = Vec::new();
|
||||||
|
|
||||||
|
for signal in signals {
|
||||||
|
let tx_ = Arc::clone(&tx);
|
||||||
|
let num = *signal as u8;
|
||||||
|
|
||||||
|
let sigid = unsafe {
|
||||||
|
signal_hook::low_level::register(*signal, move || {
|
||||||
|
let _ = unistd::write(&tx_, &[num]);
|
||||||
|
})
|
||||||
|
}?;
|
||||||
|
|
||||||
|
sigids.push(sigid);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Self { sigids, rx })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn flush(&self) {
|
fn flush(&mut self) -> Vec<i32> {
|
||||||
let mut buf = [0; 256];
|
let mut buf = [0; 256];
|
||||||
|
let mut signals = Vec::new();
|
||||||
|
|
||||||
while let Ok(n) = unistd::read(&self.rx, &mut buf) {
|
while let Ok(n) = unistd::read(&self.rx, &mut buf) {
|
||||||
|
for num in &buf[..n] {
|
||||||
|
signals.push(*num as i32);
|
||||||
|
}
|
||||||
|
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
signals
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -376,7 +363,9 @@ impl AsFd for SignalFd {
|
|||||||
|
|
||||||
impl Drop for SignalFd {
|
impl Drop for SignalFd {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
signal_hook::low_level::unregister(self.sigid);
|
for sigid in &self.sigids {
|
||||||
|
signal_hook::low_level::unregister(*sigid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user