Using a mutable reference before shutting down a program

I'm trying to save the state of my program before receiving SIGTERM.

The main function looks like this:

fn main() -> Result<(), Error> {
    let mut state = State::new();

    unsafe { signal_hook::register(signal_hook::SIGTERM, move || on_shutdown(&mut state)) }?;

    loop { read_eval_print(&mut state); }
}

The on_shutdown function does 3 things:

  • serializes State into a String, by calling a function serialize(&mut State) -> String;
  • writes the serialized string to a file;
  • calls process::abort().

I'm having difficulties getting it to compile. The error I'm seeing is "cannot borrow state as mutable".

Shouldn't I be allowed to use state in this context? Since it won't be reused anyway, in theory...

Any ideas how to get around this?

Well you are moving an &mut State into the closure, and mutable references always require exclusive access to the pointee. This means that if the shutdown hook has a mutable reference, nothing else can access state while that hook exists.

1 Like

SIGTERM can get delivered at any point, including points where state is in an inconsistent state, like in the middle of a write. Also LLVM optimizes based on the assumption that the State passed to read_eval_print is not modified for the duration of the call. This includes the ability to keep (some) updates in registers and only apply them when returning from read_eval_print.

As workaround you could set a static AtomicBool from the signal handler and check for it inside the loop of read_eval_print. If you want the read to be interruptible, you could avoid using read_line and instead use read. If the error returned from read is ErrorKind::Interrupted, that means a signal was delivered. Read the AtomicBool and if it is not set, you should retry the read. If it is set you should return from read_eval_print.

The other option is to store a clone of state in a static and access that one from the signal handler. Just make sure that you don't use a mutex, to prevent deadlocks. Instead use AtomicPtr or better crossbeam::AtomicCell.

3 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.