1

Is it possible to interrupt/cancel io::stdin().read_line() or interrupt stdin read before returning on a newline?

I have one thread polling for signals, which when received SIGINT should stop io::stdin().read_line().

use std::io::Write;
use std::{io, thread};
use std::error::Error;
use std::sync::{Arc, atomic::AtomicUsize, atomic::Ordering};
use signal_hook::consts::signal;
use signal_hook::flag;

const SIGINT_U: usize = signal::SIGINT as usize;

fn main() -> Result<(), Box<dyn Error>> {
    let term = Arc::new(AtomicUsize::new(0));
    signal_hook::flag::register_usize(signal::SIGINT, Arc::clone(&term), SIGINT_U).unwrap();
    thread::spawn(move || loop {
        match term.load(Ordering::Relaxed) {
            0 => {
                // do nothing
            }, 
            SIGINT_U => {
                // interrupt running read_line()
            }, 
            _ => unreachable!()
        }
    });

    loop {
        print!("> ");
        io::stdout().flush().unwrap();

        let mut line = String::new();
        io::stdin()
            .read_line(&mut line)
            .expect("Failed to read stdin");

        let command = line.trim_end().trim_start().to_lowercase();
        if command == "exit" {
            break;
        }

        println!("received: {}", line);
    }
}

The effect should be the same if we instead put io::stdin().read_line() into a separate thread and the SIGINT check inside the main loop.

The problem is, when read_line() is reached, stdin won't stop being read until a newline character is reached. This is the standard and expected behavior, but I'd hope I could somehow stop its execution. Albeit through stopping killing a thread running it, or somehow cancelling its return and stop without reading stdin.

I did try to put read_line() on a separate thread and detect when SIGINT was received. But it wouldn't matter, because the thread loop can't be stopped while read_line() executes, only before or after it.

I thought that maybe I could kill the thread running read_line(), but apparently it's not possible to kill threads.

Willian
  • 31
  • 1
  • 6
  • Which operating system? – Finomnis May 07 '23 at 06:52
  • I'm not sure if it's possible to achieve what you are asking for using the normal `std::io` library. Would you be open to switch to [async_std](https://docs.rs/async-std/latest/async_std/)? Because with it, your problem would be trivial. – Finomnis May 07 '23 at 06:56
  • Does this answer your question? [How can I read non-blocking from stdin?](https://stackoverflow.com/questions/30012995/how-can-i-read-non-blocking-from-stdin) – drewtato May 07 '23 at 07:10
  • thanks for the suggestion @drewtato, but I've already tested this exact solution before hand and even mentioned it on the question: _"The effect should be the same if we instead put io::stdin().read_line() into a separate thread"_ – Willian May 07 '23 at 17:03
  • @Finomnis thanks! I'll try to look into async. I'm trying to do this on Windows, but I wanted a simple and as portable way as possible. – Willian May 07 '23 at 17:11

0 Answers0