I made a library that's used by a larger application. The application calls some function of my library, which is blocking. Currently, you cannot interrupt the application while my library's code is running. I want to be able to terminate my library with Ctrl+C, which should:
Run some cleanup actions, including killing a process, starting a process, and writing to files. This does not need to be interruptible; e.g. a second Ctrl+C does not need to do anything.
Return an Err(Error::Interrupted) to the application, letting it handle the error, and continue running if it wants.
However, I don't want any trace of my signal handling to be left after my library's function finishes executing. What is the best way to do this?
Signal handlers are a process global resource. As a library you probably shouldn't register signal handlers in case they will conflict with those set by the main program. You could try asking your users to register a signal handler instead and expose a function that should be called on SIGINT (but probably not from within the signal handler as some of the things you do are not async-signal-safe).
I will clear up what I mean a little bit:
My "library" (jetbrains-toolbox-updater) is just an application that exposes a single function to run the entire thing as a library, to allow the big application to run it. Its library has exactly one user, the big application (topgrade). I could've made topgrade parse the output of jetbrains-toolbox-updater, but I didn't want to distribute them separately. That is why it's a library at all.
I have control of topgrade. Topgrade sets a signal handler, but the signal handler only sets an AtomicBool that is unset afterwards, to check whether a subprocess was killed by Ctrl+C, or by exiting by itself. I do not care about any other applications using jetbrains-toolbox-updater as a library.
I want to keep jetbrains-toolbox-updater as decoupled from topgrade as possible. It should be usable as an application by itself.
Do you think this justifies a temporary signal handler? Or is there a better solution I'm missing?
I see. Would it make sense to have topgrade spawn std::env::current_exe() with an argument to tell it to only invoke jetbrains-toolbox-updater and then exit? If so you can permanently register the signal handler for jetbrains-toolbox-updater in the child process.