use base::prelude::*;
use core::{mem};
use core::ops::{Eq};
use base::undef::{UndefState};
use base::{error};
use atomic::{Atomic};
use {arch_fns};
const UNLOCKED: u8 = 0;
const LOCKED: u8 = 1;
pub enum SpinLockStatus {
Unlocked,
Locked,
}
#[repr(C)]
pub struct SpinLock {
val: Atomic<u8>,
}
impl Eq for SpinLock {
fn eq(&self, other: &SpinLock) -> bool {
mem::addr(self) == mem::addr(other)
}
}
impl<'a> SpinLock {
pub const fn new() -> SpinLock {
SpinLock { val: Atomic::new(UNLOCKED) }
}
fn guard(&'a self) -> SpinLockGuard<'a> {
SpinLockGuard { lock: self }
}
pub unsafe fn unlock(&self) {
self.guard();
}
pub unsafe fn as_atomic(&self) -> &Atomic<u8> {
&self.val
}
pub fn status(&self) -> SpinLockStatus {
match self.val.load_unordered() {
UNLOCKED => SpinLockStatus::Unlocked,
_ => SpinLockStatus::Locked,
}
}
pub fn try_lock(&'a self) -> Result<SpinLockGuard<'a>> {
if self.val.compare_exchange_acquire(UNLOCKED, LOCKED) == UNLOCKED {
Ok(self.guard())
} else {
Err(error::ResourceBusy)
}
}
pub fn lock(&'a self) -> SpinLockGuard<'a> {
while self.val.compare_exchange_acquire(UNLOCKED, LOCKED) != UNLOCKED {
arch_fns::spin();
}
self.guard()
}
}
unsafe impl UndefState for SpinLock {
fn num() -> usize { u8::max() as usize - 1 }
unsafe fn set_undef(val: *mut SpinLock, n: usize) {
assert!(n < Self::num());
assert!(mem::size_of::<SpinLock>() == mem::size_of::<u8>());
*(val as *mut u8) = n as u8 + 2;
}
unsafe fn is_undef(val: *const SpinLock, n: usize) -> bool {
assert!(mem::size_of::<SpinLock>() == mem::size_of::<u8>());
*(val as *const u8) == n as u8 + 2
}
}
pub struct SpinLockGuard<'a> {
lock: &'a SpinLock,
}
impl<'a> SpinLockGuard<'a> {
pub fn as_lock(&self) -> &'a SpinLock {
self.lock
}
pub fn unlock(self) -> &'a SpinLock {
self.lock
}
}
impl<'a> Drop for SpinLockGuard<'a> {
fn drop(&mut self) {
self.lock.val.store_release(UNLOCKED);
}
}