mirror of
https://github.com/rust-lang/rust.git
synced 2024-12-03 12:13:43 +00:00
std: add a NativeMutex type as a wrapper to destroy StaticNativeMutex.
This obsoletes LittleLock, and so it is removed.
This commit is contained in:
parent
b87ed605c0
commit
0937f65999
@ -17,10 +17,10 @@ use std::rt::local::Local;
|
||||
use std::rt::rtio;
|
||||
use std::rt::task::{Task, BlockedTask};
|
||||
use std::task::TaskOpts;
|
||||
use std::unstable::sync::LittleLock;
|
||||
use std::unstable::mutex::NativeMutex;
|
||||
|
||||
struct SimpleTask {
|
||||
lock: LittleLock,
|
||||
lock: NativeMutex,
|
||||
awoken: bool,
|
||||
}
|
||||
|
||||
@ -59,9 +59,9 @@ impl Runtime for SimpleTask {
|
||||
to_wake.put_runtime(self as ~Runtime);
|
||||
unsafe {
|
||||
cast::forget(to_wake);
|
||||
let _l = (*me).lock.lock();
|
||||
let mut guard = (*me).lock.lock();
|
||||
(*me).awoken = true;
|
||||
(*me).lock.signal();
|
||||
guard.signal();
|
||||
}
|
||||
}
|
||||
|
||||
@ -83,7 +83,7 @@ impl Runtime for SimpleTask {
|
||||
pub fn task() -> ~Task {
|
||||
let mut task = ~Task::new();
|
||||
task.put_runtime(~SimpleTask {
|
||||
lock: LittleLock::new(),
|
||||
lock: unsafe {NativeMutex::new()},
|
||||
awoken: false,
|
||||
} as ~Runtime);
|
||||
return task;
|
||||
|
@ -23,7 +23,7 @@
|
||||
use std::cast;
|
||||
use std::libc::{c_void, c_int};
|
||||
use std::rt::task::BlockedTask;
|
||||
use std::unstable::sync::LittleLock;
|
||||
use std::unstable::mutex::NativeMutex;
|
||||
use std::sync::arc::UnsafeArc;
|
||||
use mpsc = std::sync::mpsc_queue;
|
||||
|
||||
@ -39,7 +39,7 @@ enum Message {
|
||||
|
||||
struct State {
|
||||
handle: *uvll::uv_async_t,
|
||||
lock: LittleLock, // see comments in async_cb for why this is needed
|
||||
lock: NativeMutex, // see comments in async_cb for why this is needed
|
||||
queue: mpsc::Queue<Message>,
|
||||
}
|
||||
|
||||
@ -112,7 +112,7 @@ impl QueuePool {
|
||||
let handle = UvHandle::alloc(None::<AsyncWatcher>, uvll::UV_ASYNC);
|
||||
let state = UnsafeArc::new(State {
|
||||
handle: handle,
|
||||
lock: LittleLock::new(),
|
||||
lock: unsafe {NativeMutex::new()},
|
||||
queue: mpsc::Queue::new(),
|
||||
});
|
||||
let q = ~QueuePool {
|
||||
|
@ -8,44 +8,50 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! A native mutex and condition variable type
|
||||
//! A native mutex and condition variable type.
|
||||
//!
|
||||
//! This module contains bindings to the platform's native mutex/condition
|
||||
//! variable primitives. It provides a single type, `StaticNativeMutex`, which can be
|
||||
//! statically initialized via the `NATIVE_MUTEX_INIT` value. This object serves as
|
||||
//! both a mutex and a condition variable simultaneously.
|
||||
//! variable primitives. It provides two types: `StaticNativeMutex`, which can
|
||||
//! be statically initialized via the `NATIVE_MUTEX_INIT` value, and a simple
|
||||
//! wrapper `NativeMutex` that has a destructor to clean up after itself. These
|
||||
//! objects serve as both mutexes and condition variables simultaneously.
|
||||
//!
|
||||
//! The lock is lazily initialized, but it can only be unsafely destroyed. A
|
||||
//! statically initialized lock doesn't necessarily have a time at which it can
|
||||
//! get deallocated. For this reason, there is no `Drop` implementation of the
|
||||
//! mutex, but rather the `destroy()` method must be invoked manually if
|
||||
//! destruction of the mutex is desired.
|
||||
//! The static lock is lazily initialized, but it can only be unsafely
|
||||
//! destroyed. A statically initialized lock doesn't necessarily have a time at
|
||||
//! which it can get deallocated. For this reason, there is no `Drop`
|
||||
//! implementation of the static mutex, but rather the `destroy()` method must
|
||||
//! be invoked manually if destruction of the mutex is desired.
|
||||
//!
|
||||
//! It is not recommended to use this type for idiomatic rust use. This type is
|
||||
//! appropriate where no other options are available, but other rust concurrency
|
||||
//! primitives should be used before this type.
|
||||
//! The non-static `NativeMutex` type does have a destructor, but cannot be
|
||||
//! statically initialized.
|
||||
//!
|
||||
//! It is not recommended to use this type for idiomatic rust use. These types
|
||||
//! are appropriate where no other options are available, but other rust
|
||||
//! concurrency primitives should be used before them.
|
||||
//!
|
||||
//! # Example
|
||||
//!
|
||||
//! use std::unstable::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
|
||||
//!
|
||||
//! // Use a statically initialized mutex
|
||||
//! static mut lock: StaticNativeMutex = NATIVE_MUTEX_INIT;
|
||||
//! static mut LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT;
|
||||
//!
|
||||
//! unsafe {
|
||||
//! let _guard = lock.lock();
|
||||
//! let _guard = LOCK.lock();
|
||||
//! } // automatically unlocked here
|
||||
//!
|
||||
//! // Use a normally initialized mutex
|
||||
//! unsafe {
|
||||
//! let mut lock = StaticNativeMutex::new();
|
||||
//! let mut lock = NativeMutex::new();
|
||||
//!
|
||||
//! {
|
||||
//! let _guard = lock.lock();
|
||||
//! } // unlocked here
|
||||
//!
|
||||
//! // sometimes the RAII guard isn't appropriate
|
||||
//! lock.lock_noguard();
|
||||
//! lock.unlock_noguard();
|
||||
//!
|
||||
//! lock.destroy();
|
||||
//! }
|
||||
//! } // `lock` is deallocated here
|
||||
|
||||
#[allow(non_camel_case_types)];
|
||||
|
||||
@ -54,10 +60,20 @@ use ops::Drop;
|
||||
|
||||
/// A native mutex suitable for storing in statics (that is, it has
|
||||
/// the `destroy` method rather than a destructor).
|
||||
///
|
||||
/// Prefer the `NativeMutex` type where possible.
|
||||
pub struct StaticNativeMutex {
|
||||
priv inner: imp::Mutex,
|
||||
}
|
||||
|
||||
/// A native mutex with a destructor for clean-up.
|
||||
///
|
||||
/// See `StaticNativeMutex` for a version that is suitable for storing in
|
||||
/// statics.
|
||||
pub struct NativeMutex {
|
||||
priv inner: StaticNativeMutex
|
||||
}
|
||||
|
||||
/// Automatically unlocks the mutex that it was created from on
|
||||
/// destruction.
|
||||
///
|
||||
@ -144,6 +160,72 @@ impl StaticNativeMutex {
|
||||
pub unsafe fn destroy(&mut self) { self.inner.destroy() }
|
||||
}
|
||||
|
||||
impl NativeMutex {
|
||||
/// Creates a new mutex.
|
||||
///
|
||||
/// The user must be careful to ensure the mutex is not locked when its is
|
||||
/// being destroyed.
|
||||
pub unsafe fn new() -> NativeMutex {
|
||||
NativeMutex { inner: StaticNativeMutex::new() }
|
||||
}
|
||||
|
||||
/// Acquires this lock. This assumes that the current thread does not
|
||||
/// already hold the lock.
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// use std::unstable::mutex::NativeMutex;
|
||||
/// let mut lock = NativeMutex::new();
|
||||
/// unsafe {
|
||||
/// let _guard = lock.lock();
|
||||
/// // critical section...
|
||||
/// } // automatically unlocked in `_guard`'s destructor
|
||||
/// ```
|
||||
pub unsafe fn lock<'a>(&'a mut self) -> LockGuard<'a> {
|
||||
self.inner.lock()
|
||||
}
|
||||
|
||||
/// Attempts to acquire the lock. The value returned is `Some` if
|
||||
/// the attempt succeeded.
|
||||
pub unsafe fn trylock<'a>(&'a mut self) -> Option<LockGuard<'a>> {
|
||||
self.inner.trylock()
|
||||
}
|
||||
|
||||
/// Acquire the lock without creating a `LockGuard`.
|
||||
///
|
||||
/// Prefer using `.lock`.
|
||||
pub unsafe fn lock_noguard(&mut self) { self.inner.lock_noguard() }
|
||||
|
||||
/// Attempts to acquire the lock without creating a
|
||||
/// `LockGuard`. The value returned is whether the lock was
|
||||
/// acquired or not.
|
||||
///
|
||||
/// Prefer using `.trylock`.
|
||||
pub unsafe fn trylock_noguard(&mut self) -> bool {
|
||||
self.inner.trylock_noguard()
|
||||
}
|
||||
|
||||
/// Unlocks the lock. This assumes that the current thread already holds the
|
||||
/// lock.
|
||||
pub unsafe fn unlock_noguard(&mut self) { self.inner.unlock_noguard() }
|
||||
|
||||
/// Block on the internal condition variable.
|
||||
///
|
||||
/// This function assumes that the lock is already held. Prefer
|
||||
/// using `LockGuard.wait` since that guarantees that the lock is
|
||||
/// held.
|
||||
pub unsafe fn wait_noguard(&mut self) { self.inner.wait_noguard() }
|
||||
|
||||
/// Signals a thread in `wait` to wake up
|
||||
pub unsafe fn signal_noguard(&mut self) { self.inner.signal_noguard() }
|
||||
}
|
||||
|
||||
impl Drop for NativeMutex {
|
||||
fn drop(&mut self) {
|
||||
unsafe {self.inner.destroy()}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> LockGuard<'a> {
|
||||
/// Block on the internal condition variable.
|
||||
pub unsafe fn wait(&mut self) {
|
||||
|
@ -10,51 +10,11 @@
|
||||
|
||||
use clone::Clone;
|
||||
use kinds::Send;
|
||||
use ops::Drop;
|
||||
use option::Option;
|
||||
use sync::arc::UnsafeArc;
|
||||
use unstable::mutex::{StaticNativeMutex, LockGuard};
|
||||
|
||||
pub struct LittleLock {
|
||||
priv l: StaticNativeMutex,
|
||||
}
|
||||
|
||||
pub struct LittleGuard<'a> {
|
||||
priv l: LockGuard<'a>
|
||||
}
|
||||
|
||||
impl Drop for LittleLock {
|
||||
fn drop(&mut self) {
|
||||
unsafe { self.l.destroy(); }
|
||||
}
|
||||
}
|
||||
|
||||
impl LittleLock {
|
||||
pub fn new() -> LittleLock {
|
||||
unsafe { LittleLock { l: StaticNativeMutex::new() } }
|
||||
}
|
||||
|
||||
pub unsafe fn lock<'a>(&'a mut self) -> LittleGuard<'a> {
|
||||
LittleGuard { l: self.l.lock() }
|
||||
}
|
||||
|
||||
pub unsafe fn try_lock<'a>(&'a mut self) -> Option<LittleGuard<'a>> {
|
||||
self.l.trylock().map(|guard| LittleGuard { l: guard })
|
||||
}
|
||||
|
||||
pub unsafe fn signal(&mut self) {
|
||||
self.l.signal_noguard();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> LittleGuard<'a> {
|
||||
pub unsafe fn wait(&mut self) {
|
||||
self.l.wait();
|
||||
}
|
||||
}
|
||||
use unstable::mutex::NativeMutex;
|
||||
|
||||
struct ExData<T> {
|
||||
lock: LittleLock,
|
||||
lock: NativeMutex,
|
||||
failed: bool,
|
||||
data: T,
|
||||
}
|
||||
@ -83,7 +43,7 @@ impl<T:Send> Clone for Exclusive<T> {
|
||||
impl<T:Send> Exclusive<T> {
|
||||
pub fn new(user_data: T) -> Exclusive<T> {
|
||||
let data = ExData {
|
||||
lock: LittleLock::new(),
|
||||
lock: unsafe {NativeMutex::new()},
|
||||
failed: false,
|
||||
data: user_data
|
||||
};
|
||||
@ -92,8 +52,8 @@ impl<T:Send> Exclusive<T> {
|
||||
}
|
||||
}
|
||||
|
||||
// Exactly like std::arc::MutexArc,access(), but with the LittleLock
|
||||
// instead of a proper mutex. Same reason for being unsafe.
|
||||
// Exactly like sync::MutexArc.access(). Same reason for being
|
||||
// unsafe.
|
||||
//
|
||||
// Currently, scheduling operations (i.e., descheduling, receiving on a pipe,
|
||||
// accessing the provided condition variable) are prohibited while inside
|
||||
@ -119,14 +79,14 @@ impl<T:Send> Exclusive<T> {
|
||||
#[inline]
|
||||
pub unsafe fn hold_and_signal(&self, f: |x: &mut T|) {
|
||||
let rec = self.x.get();
|
||||
let _l = (*rec).lock.lock();
|
||||
let mut guard = (*rec).lock.lock();
|
||||
if (*rec).failed {
|
||||
fail!("Poisoned Exclusive::new - another task failed inside!");
|
||||
}
|
||||
(*rec).failed = true;
|
||||
f(&mut (*rec).data);
|
||||
(*rec).failed = false;
|
||||
(*rec).lock.signal();
|
||||
guard.signal();
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
Loading…
Reference in New Issue
Block a user