summaryrefslogblamecommitdiff
path: root/src/mutex.rs
blob: 1da38908734c58d8a101fd3f169cb5b9b06e7cba (plain) (tree)




























































                                                  
use core::ops::{Deref, DerefMut};
use core::cell::UnsafeCell;

pub struct Mutex<T> {
    res: UnsafeCell<T>,
    locked: u8
}

pub struct MutexGuard<'a, T: 'a> {
    lock: &'a Mutex<T>
}

impl<'a, T> Drop for MutexGuard<'a, T> {
    fn drop(&mut self) {
        unsafe {
            asm!("ldr r2, $0
                  mov r1, $1
                  dmb
                  str r1, [r2]"
                :
                : "m"(&self.lock.locked), "i"(0));
        }
    }
}

impl<'a, T> Deref for MutexGuard<'a, T> {
    type Target = T;
    fn deref(&self) -> &Self::Target {
        unsafe { &*self.lock.res.get() }
    }
}

impl<'a, T> DerefMut for MutexGuard<'a, T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        unsafe { &mut *self.lock.res.get() }
    }
}

impl<T> Mutex<T> {
    pub fn new(t: T) -> Mutex<T> {
        Mutex{res: UnsafeCell::new(t), locked: 0}
    }
    pub fn lock(&self) -> MutexGuard<T> {
        unsafe {
            asm!("ldr r2, $0
                  mov r1, $1
                  spin_lock:
                  ldrex r0, [r2]
                  cmp r0, $1
                  itt ne
                  strexbne r0, r1, [r2]
                  cmpne r0, #1
                  beq spin_lock
                  dmb"
              :
              : "m"(&self.locked), "i"(1)
              : "r2", "r1", "r0");
        }
        MutexGuard{lock: self}
    }
}