Skip to content

Invoking previously registered action #130

@hniksic

Description

@hniksic

I have a stats library which I'd like to have the option of printing its stats on ^C. So I wrote something like this:

pub fn report_on_interrupt() {
    let mut signals = Signals::new(&[SIGINT]).unwrap();
    thread::Builder::new()
        .name("SIGINT helper".to_string())
        .spawn(move || {
            for _ in signals.forever() {
                dump_stat_reports();
                let _ = signal_hook::low_level::emulate_default_handler(SIGINT);
                std::process::exit(255); // just in case
            }
        })
        .unwrap();
}

This works nicely - if you interrupt the program with ^C, a report gets printed, and the program exists as if ^C were pressed (the shell reports an exit status of 130).

But this approach will clobber someone else who installs a SIGINT hook - my cleanup code just executes the default action, where I'd like it to remember the previously installed action and execute that. So I wrote something like this:

pub fn report_on_interrupt() {
    // safety: we don't install a useful action, we call this for side effect of getting the previous action
    let orig_action = unsafe {
        signal_hook::low_level::register(SIGINT, || ()).unwrap()
    };
    let mut signals = Signals::new(&[SIGINT]).unwrap();
    thread::Builder::new()
        .name("SIGINT helper".to_string())
        .spawn(move || {
            for _ in signals.forever() {
                dump_stat_reports();
                signal_hook::low_level::unregister(orig_action);
                let _ = signal_hook::low_level::raise(SIGINT);
                std::process::exit(255); // just in case
            }
        })
        .unwrap();
}

Of course, the above doesn't work, It always exits with 255 - first, because unregister doesn't restore the previous action, it just removes the dummy one we've installed. And second because unregister docs explicitly specify that it will never restore the default terminating action.

Is it possible to implement the behavior I'd like using signal_hook?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions