lib: non-blocking daemon shutdown

This makes it possible to trigger the shutdown of the daemon through the
DaemonHandle, without having to block while waiting for the poller
thread to join.

Incidently, this allows to avoid having to move `self` which in turns
allows to fix a GUI bug (see
https://github.com/wizardsardine/liana/issues/622).

Only available as an optional feature since `is_finished` needs rustc
1.61.
This commit is contained in:
Antoine Poinsot 2023-08-22 14:19:24 +02:00
parent bdeaf93ec8
commit 2a6b775f60
No known key found for this signature in database
GPG Key ID: E13FC145CD3F4304
3 changed files with 27 additions and 2 deletions

View File

@ -22,6 +22,7 @@ required-features = ["daemon"]
[features]
default = ["daemon"]
daemon = ["libc"]
nonblocking_shutdown = []
[dependencies]
# For managing transactions (it re-exports the bitcoin crate)

View File

@ -36,11 +36,23 @@ impl Poller {
Poller { shutdown, handle }
}
pub fn stop(self) {
pub fn trigger_stop(&self) {
self.shutdown.store(true, atomic::Ordering::Relaxed);
}
pub fn stop(self) {
self.trigger_stop();
self.handle.join().expect("The poller loop must not fail");
}
#[cfg(feature = "nonblocking_shutdown")]
pub fn is_stopped(&self) -> bool {
// Doc says "This might return true for a brief moment after the threads main function has
// returned, but before the thread itself has stopped running.". But it's not an issue for
// us, as long as the main poller function has returned we are good.
self.handle.is_finished()
}
#[cfg(test)]
pub fn test_stop(&mut self) {
self.shutdown.store(true, atomic::Ordering::Relaxed);

View File

@ -458,12 +458,24 @@ impl DaemonHandle {
Ok(())
}
// NOTE: this moves out the data as it should not be reused after shutdown
/// Shut down the Liana daemon.
pub fn shutdown(self) {
self.bitcoin_poller.stop();
}
/// Tell the daemon to shut down. This will return before the shutdown completes. The structure
/// must not be reused after triggering shutdown.
#[cfg(feature = "nonblocking_shutdown")]
pub fn trigger_shutdown(&self) {
self.bitcoin_poller.trigger_stop()
}
/// Whether the daemon has finished shutting down.
#[cfg(feature = "nonblocking_shutdown")]
pub fn shutdown_complete(&self) -> bool {
self.bitcoin_poller.is_stopped()
}
// We need a shutdown utility that does not move for implementing Drop for the DummyLiana
#[cfg(test)]
pub fn test_shutdown(&mut self) {