use std::{sync::Arc, time::Instant};
use futures::{future::pending, FutureExt};
use slab::Slab;
use tokio::sync::{Mutex, OwnedMutexGuard};
#[derive(Debug, Default)]
pub struct HostMutex {
inner: Arc<Mutex<()>>,
lock: Option<OwnedMutexGuard<()>>,
}
#[derive(Debug, Default)]
pub struct MutexPool {
mutexes: Slab<HostMutex>,
}
impl MutexPool {
pub fn create_mutex(&mut self) -> usize {
self.mutexes.insert(HostMutex::default())
}
pub fn delete_mutex(&mut self, mutex_id: usize) {
self.mutexes.remove(mutex_id);
}
pub async fn lock(&mut self, mutex_id: usize, timeout: Option<Instant>) -> bool {
let sleep = timeout.map_or_else(
|| pending().boxed(),
|i| tokio::time::sleep_until(i.into()).boxed(),
);
let mutex = self.mutexes.get_mut(mutex_id).unwrap();
tokio::select! {
biased;
lock = mutex.inner.clone().lock_owned() => {
mutex.lock = Some(lock);
true
}
_ = sleep => false,
}
}
pub fn unlock(&mut self, mutex_id: usize) {
let mutex = self.mutexes.get_mut(mutex_id).unwrap();
mutex.lock.take().unwrap();
}
}