Как поймать сигналы в Rust

Я пытаюсь написать код, который поймает сигнал типа SIGTERM.

Я нашел this, и я также нашел Как обрабатывать блокировку ввода/вывода в Rust, или длительные вызовы внешних функций в целом.

Но в текущей версии Rust (0.12 в ночное время) кажется, что std::io::signal::Listener был удален. Он попал куда-то еще? Если это так, кто-то может указать мне, как поймать сигнал?

Ответ 1

Я считаю, что модуль std::io::signal был удален в this pull request. Утверждается, что правильная обработка сигналов никогда не была должным образом реализована для собственной среды выполнения, поэтому вы, вероятно, не сможете ее использовать в любом случае. Это, кажется, проблема отслеживания этой проблемы.

Тем временем, я думаю, вам нужно будет спуститься до небезопасных функций самого низкого уровня из libc.

Ответ 2

На момент написания этого ответа имеется RFC для встроенных сигналов.

У меня был некоторый успех при использовании ящика с chan-signal:

#[macro_use]
extern crate chan;
extern crate chan_signal;

use chan_signal::Signal;

fn main() {
    // Signal gets a value when the OS sent a INT or TERM signal.
    let signal = chan_signal::notify(&[Signal::INT, Signal::TERM]);
    // When our work is complete, send a sentinel value on 'sdone'.
    let (sdone, rdone) = chan::sync(0);
    // Run work.
    ::std::thread::spawn(move || run(sdone));

    // Wait for a signal or for work to be done.
    chan_select! {
        signal.recv() -> signal => {
            println!("received signal: {:?}", signal)
        },
        rdone.recv() => {
            println!("Program completed normally.");
        }
    }
}

fn run(_sdone: chan::Sender<()>) {
    println!("Running work for 5 seconds.");
    println!("Can you send a signal quickly enough?");
    // Do some work.
    ::std::thread::sleep_ms(5000);

    // _sdone gets dropped which closes the channel and causes 'rdone'
    // to unblock.
}

Ответ 3

Кажется, что теперь это довольно тривиально реализовать это. Раздел Обработка сигналов в Приложениях командной строки в Rust выходит за рамки этой концепции и упоминает ящик ctrlc для обработки этого конкретного сигнала, а также ящик для подключения сигналов для обработки сигналов в целом.

С помощью гида с сигнальным крючком это должно быть так просто, как:

use std::{error::Error, thread};
use signal_hook::{iterator::Signals, SIGTERM};

fn main() -> Result<(), Box<Error>> {
    let signals = Signals::new(&[SIGTERM])?;

    thread::spawn(move || {
        for sig in signals.forever() {
            println!("Received signal {:?}", sig);
        }
    });

    Ok(())
}