use std::cell::UnsafeCell;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Mutex, MutexGuard};
pub trait MonitorCore<COORD, CRIT, WS> {
fn acquire<'a: 'b, 'b>(
&self,
guard: MutexGuard<'a, COORD>,
t: &'b mut WS,
) -> (bool, MutexGuard<'a, COORD>);
fn release<'a: 'b, 'b>(
&self,
guard: MutexGuard<'a, COORD>,
t: &'b mut WS,
) -> MutexGuard<'a, COORD>;
fn critical_section<'a: 'b, 'b>(&self, crit: &'a mut CRIT, t: &'b mut WS);
}
pub struct Monitor<COORD, CRIT, WS, M: MonitorCore<COORD, CRIT, WS>> {
core: M,
coordination: Mutex<COORD>,
synchronization: AtomicBool,
critical_section: UnsafeCell<CRIT>,
_phantom_ws: std::marker::PhantomData<WS>,
}
impl<COORD, CRIT, WS, M: MonitorCore<COORD, CRIT, WS>> Monitor<COORD, CRIT, WS, M> {
pub fn new(core: M, coordination: COORD, critical_section: CRIT) -> Self {
Self {
core,
coordination: Mutex::new(coordination),
synchronization: AtomicBool::new(false),
critical_section: UnsafeCell::new(critical_section),
_phantom_ws: std::marker::PhantomData,
}
}
pub fn do_it<'a: 'a, 'b>(&'a self, t: &'b mut WS) {
{
let coordination = self.coordination.lock().unwrap();
let (acquired, _coordination) = self.core.acquire(coordination, t);
if !acquired {
return;
}
if self.synchronization.swap(true, Ordering::Acquire) {
panic!("synchronization invariant violated: acquire should only allow one thread at a time in the critical section");
}
}
let crit: &mut CRIT = unsafe { &mut *self.critical_section.get() };
self.core.critical_section(crit, t);
let coordination = self.coordination.lock().unwrap();
self.synchronization.store(false, Ordering::Release);
drop(self.core.release(coordination, t));
}
pub fn decompose(self) -> (M, COORD, CRIT) {
(
self.core,
self.coordination.into_inner().unwrap(),
self.critical_section.into_inner(),
)
}
}
unsafe impl<COORD: Send, CRIT: Send, WS, M: MonitorCore<COORD, CRIT, WS>> Send
for Monitor<COORD, CRIT, WS, M>
{
}
unsafe impl<COORD: Send, CRIT: Send, WS, M: MonitorCore<COORD, CRIT, WS>> Sync
for Monitor<COORD, CRIT, WS, M>
{
}