use core::cell::UnsafeCell;
use core::ops::{Deref, DerefMut};
use avr_oxide::concurrency::{interrupt, scheduler, TryLockError, TryLockResult};
use avr_oxide::concurrency::thread;
use avr_oxide::concurrency::util::{ThreadSet, ThreadId};
struct SimpleThreadMutex {
waiting_threads: ThreadSet,
locked_by: Option<ThreadId>
}
pub struct Mutex<T: ?Sized> {
lock: UnsafeCell<SimpleThreadMutex>,
data: UnsafeCell<T>,
}
unsafe impl<T: ?Sized + Send> Send for Mutex<T> {}
unsafe impl<T: ?Sized + Send> Sync for Mutex<T> {}
#[must_use = "if unused the Mutex will immediately unlock"]
pub struct MutexGuard<'a, T: ?Sized + 'a> {
mutex: &'a Mutex<T>
}
impl<T: ?Sized> !Send for MutexGuard<'_, T> {}
unsafe impl<T: ?Sized + Sync> Sync for MutexGuard<'_, T> {}
impl SimpleThreadMutex {
fn unlocked() -> SimpleThreadMutex {
SimpleThreadMutex {
waiting_threads: ThreadSet::new(),
locked_by: None
}
}
fn try_lock(&mut self) -> Result<(),TryLockError> {
interrupt::isolated(|isotoken|{
match self.locked_by {
None => {
self.locked_by.replace(scheduler::current_thread_id(isotoken));
Ok(())
},
Some(thread_id) => {
if thread_id == scheduler::current_thread_id(isotoken) {
Ok(())
} else {
Err(TryLockError::WouldBlock)
}
}
}
})
}
fn lock(&mut self) {
loop {
for _i in 0..5 {
if self.try_lock().is_ok() {
return;
}
}
if interrupt::isolated(|isotoken|{
match self.locked_by {
None => {
self.locked_by.replace(scheduler::current_thread_id(isotoken));
true
},
Some(_other_thread_id) => {
self.waiting_threads.add_current_thread(isotoken);
scheduler::set_current_thread_state(isotoken, scheduler::ThreadState::BlockedOnMutex);
false
}
}
}) {
return
} else {
thread::yield_now();
}
}
}
fn unlock_and_release_waiting(&mut self) {
interrupt::isolated(|isotoken|{
self.locked_by.take();
scheduler::release_all_threads_and_clear(isotoken, &mut self.waiting_threads);
});
}
}
impl<T> Mutex<T> {
pub fn new(t: T) -> Mutex<T> {
Mutex {
lock: UnsafeCell::new(SimpleThreadMutex::unlocked()),
data: UnsafeCell::new(t),
}
}
}
impl<T: ?Sized> Mutex<T> {
pub fn lock(&self) -> MutexGuard<'_, T> {
unsafe {
let lock = &mut *self.lock.get();
lock.lock();
MutexGuard::new(self)
}
}
pub fn try_lock(&self) -> TryLockResult<MutexGuard<'_, T>> {
unsafe {
let lock = &mut *self.lock.get();
match lock.try_lock(){
Ok(_) => {
Ok(MutexGuard::new(self))
},
Err(e) => {
Err(e)
}
}
}
}
pub fn unlock(guard: MutexGuard<'_, T>) {
drop(guard);
}
pub fn into_inner(self) -> T
where
T: Sized
{
self.data.into_inner()
}
pub fn get_mut(&mut self) -> &mut T {
self.data.get_mut()
}
}
impl<T> From<T> for Mutex<T> {
fn from(t: T) -> Self {
Mutex::new(t)
}
}
impl<T: ?Sized + Default> Default for Mutex<T> {
fn default() -> Mutex<T> {
Mutex::new(Default::default())
}
}
impl<'mutex, T: ?Sized> MutexGuard<'mutex, T> {
unsafe fn new(lock: &'mutex Mutex<T>) -> MutexGuard<'mutex, T> {
MutexGuard { mutex: lock }
}
}
impl<T: ?Sized> Deref for MutexGuard<'_, T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.mutex.data.get() }
}
}
impl<T: ?Sized> DerefMut for MutexGuard<'_, T> {
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *self.mutex.data.get() }
}
}
impl<T: ?Sized> Drop for MutexGuard<'_, T> {
#[inline]
fn drop(&mut self) {
unsafe {
(&mut *self.mutex.lock.get()).unlock_and_release_waiting();
}
}
}