use std::{io, i32};
use std::fmt::{Debug, Formatter, Result as FmtResult};
use std::sync::atomic::Ordering;
use integer_atomics::AtomicI32;
use lock_wrappers::raw::Mutex;
use sys::{futex_wait, futex_wake};
pub struct Futex {
futex: AtomicI32
}
impl Mutex for Futex {
type LockState = ();
fn lock(&self) {
loop {
match self.futex.fetch_sub(1, Ordering::Acquire) {
1 => return, _ => {
self.futex.store(-1, Ordering::Relaxed);
match futex_wait(&self.futex, -1) {
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => (),
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => (),
Ok(_) => (),
_ => unreachable!(),
}
}
}
}
}
fn try_lock(&self) -> Option<()> {
if self.futex.compare_and_swap(1, 0, Ordering::Acquire) == 1 {
Some(())
} else {
None
}
}
fn unlock(&self, _: ()) {
match self.futex.fetch_add(1, Ordering::Release) {
0 => return, _ => {
self.futex.store(1, Ordering::Release);
futex_wake(&self.futex, i32::MAX).unwrap();
}
}
}
}
impl Default for Futex {
fn default() -> Futex {
Futex { futex: AtomicI32::new(1) }
}
}
impl Debug for Futex {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
write!(f, "Futex@{:p} (={})", &self.futex as *const _, self.futex.load(Ordering::SeqCst))
}
}