179 lines
4.2 KiB
Rust
179 lines
4.2 KiB
Rust
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
|
// file at the top-level directory of this distribution and at
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
// option. This file may not be copied, modified, or distributed
|
|
// except according to those terms.
|
|
|
|
use cell::UnsafeCell;
|
|
use intrinsics::{atomic_cxchg, atomic_xchg};
|
|
use ptr;
|
|
|
|
use sys::syscall::{futex, getpid, FUTEX_WAIT, FUTEX_WAKE};
|
|
|
|
pub unsafe fn mutex_try_lock(m: *mut i32) -> bool {
|
|
atomic_cxchg(m, 0, 1).0 == 0
|
|
}
|
|
|
|
pub unsafe fn mutex_lock(m: *mut i32) {
|
|
let mut c = 0;
|
|
//Set to larger value for longer spin test
|
|
for _i in 0..100 {
|
|
c = atomic_cxchg(m, 0, 1).0;
|
|
if c == 0 {
|
|
break;
|
|
}
|
|
//cpu_relax()
|
|
}
|
|
if c == 1 {
|
|
c = atomic_xchg(m, 2);
|
|
}
|
|
while c != 0 {
|
|
let _ = futex(m, FUTEX_WAIT, 2, 0, ptr::null_mut());
|
|
c = atomic_xchg(m, 2);
|
|
}
|
|
}
|
|
|
|
pub unsafe fn mutex_unlock(m: *mut i32) {
|
|
if *m == 2 {
|
|
*m = 0;
|
|
} else if atomic_xchg(m, 0) == 1 {
|
|
return;
|
|
}
|
|
//Set to larger value for longer spin test
|
|
for _i in 0..100 {
|
|
if *m != 0 {
|
|
if atomic_cxchg(m, 1, 2).0 != 0 {
|
|
return;
|
|
}
|
|
}
|
|
//cpu_relax()
|
|
}
|
|
let _ = futex(m, FUTEX_WAKE, 1, 0, ptr::null_mut());
|
|
}
|
|
|
|
pub struct Mutex {
|
|
pub lock: UnsafeCell<i32>,
|
|
}
|
|
|
|
impl Mutex {
|
|
/// Create a new mutex.
|
|
pub const fn new() -> Self {
|
|
Mutex {
|
|
lock: UnsafeCell::new(0),
|
|
}
|
|
}
|
|
|
|
#[inline]
|
|
pub unsafe fn init(&self) {
|
|
*self.lock.get() = 0;
|
|
}
|
|
|
|
/// Try to lock the mutex
|
|
#[inline]
|
|
pub unsafe fn try_lock(&self) -> bool {
|
|
mutex_try_lock(self.lock.get())
|
|
}
|
|
|
|
/// Lock the mutex
|
|
#[inline]
|
|
pub unsafe fn lock(&self) {
|
|
mutex_lock(self.lock.get());
|
|
}
|
|
|
|
/// Unlock the mutex
|
|
#[inline]
|
|
pub unsafe fn unlock(&self) {
|
|
mutex_unlock(self.lock.get());
|
|
}
|
|
|
|
#[inline]
|
|
pub unsafe fn destroy(&self) {
|
|
*self.lock.get() = 0;
|
|
}
|
|
}
|
|
|
|
unsafe impl Send for Mutex {}
|
|
|
|
unsafe impl Sync for Mutex {}
|
|
|
|
pub struct ReentrantMutex {
|
|
pub lock: UnsafeCell<i32>,
|
|
pub owner: UnsafeCell<usize>,
|
|
pub own_count: UnsafeCell<usize>,
|
|
}
|
|
|
|
impl ReentrantMutex {
|
|
pub const fn uninitialized() -> Self {
|
|
ReentrantMutex {
|
|
lock: UnsafeCell::new(0),
|
|
owner: UnsafeCell::new(0),
|
|
own_count: UnsafeCell::new(0),
|
|
}
|
|
}
|
|
|
|
#[inline]
|
|
pub unsafe fn init(&mut self) {
|
|
*self.lock.get() = 0;
|
|
*self.owner.get() = 0;
|
|
*self.own_count.get() = 0;
|
|
}
|
|
|
|
/// Try to lock the mutex
|
|
#[inline]
|
|
pub unsafe fn try_lock(&self) -> bool {
|
|
let pid = getpid().unwrap();
|
|
if *self.own_count.get() > 0 && *self.owner.get() == pid {
|
|
*self.own_count.get() += 1;
|
|
true
|
|
} else {
|
|
if mutex_try_lock(self.lock.get()) {
|
|
*self.owner.get() = pid;
|
|
*self.own_count.get() = 1;
|
|
true
|
|
} else {
|
|
false
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Lock the mutex
|
|
#[inline]
|
|
pub unsafe fn lock(&self) {
|
|
let pid = getpid().unwrap();
|
|
if *self.own_count.get() > 0 && *self.owner.get() == pid {
|
|
*self.own_count.get() += 1;
|
|
} else {
|
|
mutex_lock(self.lock.get());
|
|
*self.owner.get() = pid;
|
|
*self.own_count.get() = 1;
|
|
}
|
|
}
|
|
|
|
/// Unlock the mutex
|
|
#[inline]
|
|
pub unsafe fn unlock(&self) {
|
|
let pid = getpid().unwrap();
|
|
if *self.own_count.get() > 0 && *self.owner.get() == pid {
|
|
*self.own_count.get() -= 1;
|
|
if *self.own_count.get() == 0 {
|
|
*self.owner.get() = 0;
|
|
mutex_unlock(self.lock.get());
|
|
}
|
|
}
|
|
}
|
|
|
|
#[inline]
|
|
pub unsafe fn destroy(&self) {
|
|
*self.lock.get() = 0;
|
|
*self.owner.get() = 0;
|
|
*self.own_count.get() = 0;
|
|
}
|
|
}
|
|
|
|
unsafe impl Send for ReentrantMutex {}
|
|
|
|
unsafe impl Sync for ReentrantMutex {}
|