use std::collections::BinaryHeap;
use std::mem;
use std::ops::{Deref, DerefMut};
use std::sync::{self, PoisonError, TryLockError};
use std::thread;
use token::*;
use types::*;
#[derive(Debug)]
pub struct Mutex<T> {
bookkeeping: sync::Mutex<Bookkeeping>,
data: sync::Mutex<T>,
}
#[derive(Debug)]
struct Bookkeeping {
heap: BinaryHeap<PV<usize, WakeToken>>,
no_spinner: bool, }
impl<T> Mutex<T> {
pub fn new(data: T) -> Mutex<T> {
Mutex {
bookkeeping: sync::Mutex::new(Bookkeeping { heap: BinaryHeap::new(), no_spinner: true }),
data: sync::Mutex::new(data),
}
}
pub fn lock(&self, prio: usize) -> sync::LockResult<MutexGuard<T>> {
let mut bk = self.bookkeeping.lock().unwrap();
if bk.no_spinner {
bk.no_spinner = false;
mem::drop(bk);
} else {
let (sleep_token, wake_token) = create_tokens();
bk.heap.push(PV { p: prio, v: wake_token });
mem::drop(bk);
sleep_token.sleep();
}
let guard = loop {
match self.data.try_lock() {
Ok(guard) =>
break MutexGuard(guard),
Err(TryLockError::WouldBlock) =>
thread::yield_now(),
Err(TryLockError::Poisoned(pe)) =>
return Err(PoisonError::new(MutexGuard(pe.into_inner()))),
}
let mut bk = self.bookkeeping.lock().unwrap();
let (sleep_token, wake_token) = create_tokens();
bk.heap.push(PV { p: prio, v: wake_token });
bk.heap.pop().unwrap().v.wake();
mem::drop(bk);
sleep_token.sleep();
};
let mut bk = self.bookkeeping.lock().unwrap();
if let Some(x) = bk.heap.pop() {
x.v.wake();
} else {
bk.no_spinner = true;
}
Ok(guard)
}
pub fn try_lock(&self) -> sync::TryLockResult<MutexGuard<T>> {
let bk = self.bookkeeping.lock().unwrap();
if !bk.no_spinner {
return Err(TryLockError::WouldBlock);
}
mem::drop(bk);
match self.data.try_lock() {
Ok(guard) => Ok(MutexGuard(guard)),
Err(TryLockError::WouldBlock) => Err(TryLockError::WouldBlock),
Err(TryLockError::Poisoned(pe)) =>
Err(TryLockError::Poisoned(PoisonError::new(MutexGuard(pe.into_inner())))),
}
}
}
pub struct MutexGuard<'a, T: 'a>(sync::MutexGuard<'a, T>);
impl<'a, T> Deref for MutexGuard<'a, T> {
type Target = T;
fn deref(&self) -> &T {
&*self.0
}
}
impl<'a, T> DerefMut for MutexGuard<'a, T> {
fn deref_mut(&mut self) -> &mut T {
&mut *self.0
}
}