Description
Description
The new feature use-dev-tty
sometimes causes this panic:
panicked at 'polling tty: Poll(Os { code: 4, kind: Interrupted, message: "Interrupted system call" })',
XXX/.cargo/registry/src/.../crossterm-0.26.0/src/event/source/unix/tty.rs:135:28 ...
crossterm/src/event/source/unix/tty.rs
Line 135 in 383d9a7
How to reproduce
I have not found a minimal example, and my full code is not public. But I can reliably trigger it with the code below:
[dependencies]
crossterm = {version="0.26.0", features=["event-stream", "use-dev-tty"]}
futures = {version = "0.3"}
tokio = { version = "1", features = ["process", "macros", "rt-multi-thread"]}
use crossterm::event::EventStream;
use futures::{future::FutureExt, stream::StreamExt};
use std::process::Stdio;
use tokio;
#[tokio::main]
async fn main() {
let mut reader = EventStream::new();
loop {
let event = reader.next().fuse();
tokio::select! {
maybe_event = event => {
match maybe_event {
Some(Ok(event)) => println!("Event::{:?}\r", event),
Some(Err(e)) => println!("Error: {:?}\r", e),
None => break,
}
}
};
// Spawn enough tasks, and the event stream will panic.
for _ in 0..100 {
tokio::spawn(async {
// I don't think the actual command matters.
tokio::process::Command::new("pwd")
// null i/o is not needed, but I want to rule this out.
.stdin(Stdio::null())
.stdout(Stdio::null())
.stderr(Stdio::null())
.status()
.await
});
}
}
}
Note that this won't panic without the tty feature. And the panic seems to only happen with this combination (task + command). I don't know enough about tokio to be of help here.
There's another problem: When the EventStream panics, it will do it silently (not counting the panic message). At that point it will stop sending events, and the main loop is just blocked forever. Shouldn't the event stream return a Result<Event>
to handle cases where the EventSource is found to be dead? In any case, please avoid panics.
Environment
- Ubuntu 22.10
- Rust 1.69.0--nightly
- Terminal doesn't matter
I've also tested this with the current crossterm on github, with the same results.
Update:
I've changed the code to be more like the official example, which first fuses the future. This still doesn't stop the loop from being blocked after panic.