1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
use crate::Error;
use std::sync::{Mutex, MutexGuard, TryLockError};
pub(crate) struct ServiceReference {
_guard: MutexGuard<'static, ()>,
close: Box<dyn Fn() + Send + Sync>,
}
impl ServiceReference {
pub fn new<S, E>(counter: &'static Mutex<()>, start: S, close: E) -> crate::Result<Self>
where
S: FnOnce() -> crate::Result<()>,
E: Fn() + Send + Sync + 'static,
{
let _guard = match counter.try_lock() {
Ok(lock) => lock,
Err(e) => match e {
TryLockError::Poisoned(guard) => {
// If the MutexGuard is poisoned that means that the "other" service instance (of which the thread panicked)
// was NOT properly closed. To avoid any weird behaviour, we try closing the service now, to then re-open a fresh instance.
//
// It's up to our `close()` implementations to avoid panicking/doing weird stuff again.
close();
guard.into_inner()
}
TryLockError::WouldBlock => return Err(Error::ServiceAlreadyActive),
},
};
start()?;
Ok(Self {
_guard,
close: Box::new(close),
})
}
}
impl Drop for ServiceReference {
fn drop(&mut self) {
(self.close)();
}
}