it seams a XY problem to me, your example code is just trying to emulate a signal handler? in that case, you can just use the signal-hook crate, or if you only cares about SIGINT (a.k.a. Ctrl-C), you can use ctrlc, which is also much easier.
// this example uses an atomic bool and main thread polls the value,
// can also use other sync primitives, like park and unpark the main thread;
// call `process:exit()` from other thread or an signal handler not recomendded
static QUIT: AtomicBool = AtomicBool::new(false);
ctrlc::set_handler(|| {
QUIT.store(true, Ordering::SeqCst);
}).expect("Error setting Ctrl-C handler");
println!("Waiting for Ctrl-C...");
while !QUIT.load(Ordering::SeqCst) {
// just yield a little bit CPU
sleep(Duration::from_millis(5));
}
println!("Got it! Exiting...");
}
also, use stdout for keyboard input is a strong smell to me! if you are writing an interactive application, maybe use a higher level tui event loop library, instead of directly read the raw terminal input?
std::process:exit() should be used with caution, as it doens't unwind the stack, all desctructors are skipped so the side effect (such as set the terminal to raw mode in your example) will still persist after the program exits.
Are you sure ctrlc::set_handler will work in raw mode? I tried it before, and I remember it didn't detect Ctrl + C. Raw mode isn't supposed to react to normal keyboard combinations.
no, SIGINT is not delivered in raw mode cause the tty driver to translate key strokes to signals is bypassed in raw mode.
what I mean was, you can avoid using raw mode if you only need to install a signal hook, since cooked mode is easier to deal with after all (e.g. in raw mode, println!() will not work as expected, since it only write LF but no CR).
if you are writing an interactive application, I suggest to use a higher level library that handles the event loop for you, do you don't need to deal with the raw input yourself.
however, I was not saying you should never use raw tty, I was just suggesting alternative ways. if you need to handle raw tty events, that's fine, you just need to be more careful.
PS: I believe Stdout is internally synchronized with some locking mechanism, so you don't need to use mutex in the first place, just get an Stdout handle for each thread, this way you don't need to use Option to drop the handle. you just need to synchronize your threads when you enter/exit raw mode, so your screen isn't garbled.
thread::spawn(move || {
let raw_tty = std::io::stdout().into_raw_mode();
// do your stuff in raw mode
});
// main thread can use stdout without mutex
let stdout = std::io::stdout();
// synchronize with other thread, make sure raw mode is entered
stdout.write(b"\x1b[1;31mhello raw tty\r\n");