std: add an RAII unlocker to Mutex.
This automatically unlocks its lock when it goes out of scope, and provides a safe(ish) method to call .wait.
This commit is contained in:
parent
fba32ea79f
commit
76a59fd6e2
@ -669,8 +669,7 @@ impl Scheduler {
|
||||
// is acquired here. This is the resumption points and the "bounce"
|
||||
// that it is referring to.
|
||||
unsafe {
|
||||
current_task.nasty_deschedule_lock.lock();
|
||||
current_task.nasty_deschedule_lock.unlock();
|
||||
let _guard = current_task.nasty_deschedule_lock.lock();
|
||||
}
|
||||
return current_task;
|
||||
}
|
||||
@ -766,9 +765,10 @@ impl Scheduler {
|
||||
// unlocked the lock so there's no worry of this memory going away.
|
||||
let cur = self.change_task_context(cur, next, |sched, mut task| {
|
||||
let lock: *mut Mutex = &mut task.nasty_deschedule_lock;
|
||||
unsafe { (*lock).lock() }
|
||||
f(sched, BlockedTask::block(task.swap()));
|
||||
unsafe { (*lock).unlock() }
|
||||
unsafe {
|
||||
let _guard = (*lock).lock();
|
||||
f(sched, BlockedTask::block(task.swap()));
|
||||
}
|
||||
});
|
||||
cur.put();
|
||||
}
|
||||
@ -1466,12 +1466,11 @@ mod test {
|
||||
let mut handle = pool.spawn_sched();
|
||||
handle.send(PinnedTask(pool.task(TaskOpts::new(), proc() {
|
||||
unsafe {
|
||||
LOCK.lock();
|
||||
let mut guard = LOCK.lock();
|
||||
|
||||
start_ch.send(());
|
||||
LOCK.wait(); // block the scheduler thread
|
||||
LOCK.signal(); // let them know we have the lock
|
||||
LOCK.unlock();
|
||||
guard.wait(); // block the scheduler thread
|
||||
guard.signal(); // let them know we have the lock
|
||||
}
|
||||
|
||||
fin_ch.send(());
|
||||
@ -1503,10 +1502,9 @@ mod test {
|
||||
child_ch.send(20);
|
||||
pingpong(&parent_po, &child_ch);
|
||||
unsafe {
|
||||
LOCK.lock();
|
||||
LOCK.signal(); // wakeup waiting scheduler
|
||||
LOCK.wait(); // wait for them to grab the lock
|
||||
LOCK.unlock();
|
||||
let mut guard = LOCK.lock();
|
||||
guard.signal(); // wakeup waiting scheduler
|
||||
guard.wait(); // wait for them to grab the lock
|
||||
}
|
||||
})));
|
||||
drop(handle);
|
||||
|
@ -324,9 +324,8 @@ impl GreenTask {
|
||||
unsafe {
|
||||
let mtx = &mut self.nasty_deschedule_lock as *mut Mutex;
|
||||
let handle = self.handle.get_mut_ref() as *mut SchedHandle;
|
||||
(*mtx).lock();
|
||||
let _guard = (*mtx).lock();
|
||||
(*handle).send(RunOnce(self));
|
||||
(*mtx).unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -29,9 +29,8 @@ pub fn increment() {
|
||||
pub fn decrement() {
|
||||
unsafe {
|
||||
if TASK_COUNT.fetch_sub(1, atomics::SeqCst) == 1 {
|
||||
TASK_LOCK.lock();
|
||||
TASK_LOCK.signal();
|
||||
TASK_LOCK.unlock();
|
||||
let mut guard = TASK_LOCK.lock();
|
||||
guard.signal();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -40,11 +39,12 @@ pub fn decrement() {
|
||||
/// the entry points of native programs
|
||||
pub fn wait_for_other_tasks() {
|
||||
unsafe {
|
||||
TASK_LOCK.lock();
|
||||
while TASK_COUNT.load(atomics::SeqCst) > 0 {
|
||||
TASK_LOCK.wait();
|
||||
{
|
||||
let mut guard = TASK_LOCK.lock();
|
||||
while TASK_COUNT.load(atomics::SeqCst) > 0 {
|
||||
guard.wait();
|
||||
}
|
||||
}
|
||||
TASK_LOCK.unlock();
|
||||
TASK_LOCK.destroy();
|
||||
}
|
||||
}
|
||||
|
@ -222,7 +222,7 @@ pub fn init() {
|
||||
static mut INITIALIZED: bool = false;
|
||||
static mut LOCK: Mutex = MUTEX_INIT;
|
||||
|
||||
LOCK.lock();
|
||||
let _guard = LOCK.lock();
|
||||
if !INITIALIZED {
|
||||
let mut data: WSADATA = mem::init();
|
||||
let ret = WSAStartup(0x202, // version 2.2
|
||||
@ -230,7 +230,6 @@ pub fn init() {
|
||||
assert_eq!(ret, 0);
|
||||
INITIALIZED = true;
|
||||
}
|
||||
LOCK.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,7 @@ pub fn boot(helper: fn(imp::signal, Port<Req>)) {
|
||||
static mut INITIALIZED: bool = false;
|
||||
|
||||
unsafe {
|
||||
LOCK.lock();
|
||||
let mut _guard = LOCK.lock();
|
||||
if !INITIALIZED {
|
||||
let (msgp, msgc) = Chan::new();
|
||||
// promote this to a shared channel
|
||||
@ -58,7 +58,6 @@ pub fn boot(helper: fn(imp::signal, Port<Req>)) {
|
||||
rt::at_exit(proc() { shutdown() });
|
||||
INITIALIZED = true;
|
||||
}
|
||||
LOCK.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -191,20 +191,19 @@ impl rt::Runtime for Ops {
|
||||
let task = BlockedTask::block(cur_task);
|
||||
|
||||
if times == 1 {
|
||||
(*me).lock.lock();
|
||||
let mut guard = (*me).lock.lock();
|
||||
(*me).awoken = false;
|
||||
match f(task) {
|
||||
Ok(()) => {
|
||||
while !(*me).awoken {
|
||||
(*me).lock.wait();
|
||||
guard.wait();
|
||||
}
|
||||
}
|
||||
Err(task) => { cast::forget(task.wake()); }
|
||||
}
|
||||
(*me).lock.unlock();
|
||||
} else {
|
||||
let mut iter = task.make_selectable(times);
|
||||
(*me).lock.lock();
|
||||
let mut guard = (*me).lock.lock();
|
||||
(*me).awoken = false;
|
||||
let success = iter.all(|task| {
|
||||
match f(task) {
|
||||
@ -216,9 +215,8 @@ impl rt::Runtime for Ops {
|
||||
}
|
||||
});
|
||||
while success && !(*me).awoken {
|
||||
(*me).lock.wait();
|
||||
guard.wait();
|
||||
}
|
||||
(*me).lock.unlock();
|
||||
}
|
||||
// re-acquire ownership of the task
|
||||
cur_task = cast::transmute::<uint, ~Task>(cur_task_dupe);
|
||||
@ -235,10 +233,9 @@ impl rt::Runtime for Ops {
|
||||
let me = &mut *self as *mut Ops;
|
||||
to_wake.put_runtime(self as ~rt::Runtime);
|
||||
cast::forget(to_wake);
|
||||
(*me).lock.lock();
|
||||
let mut guard = (*me).lock.lock();
|
||||
(*me).awoken = true;
|
||||
(*me).lock.signal();
|
||||
(*me).lock.unlock();
|
||||
guard.signal();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,7 +75,7 @@ impl<T: Send> Packet<T> {
|
||||
select_lock: unsafe { Mutex::new() },
|
||||
};
|
||||
// see comments in inherit_blocker about why we grab this lock
|
||||
unsafe { p.select_lock.lock() }
|
||||
unsafe { p.select_lock.lock_noguard() }
|
||||
return p;
|
||||
}
|
||||
|
||||
@ -124,7 +124,7 @@ impl<T: Send> Packet<T> {
|
||||
// interfere with this method. After we unlock this lock, we're
|
||||
// signifying that we're done modifying self.cnt and self.to_wake and
|
||||
// the port is ready for the world to continue using it.
|
||||
unsafe { self.select_lock.unlock() }
|
||||
unsafe { self.select_lock.unlock_noguard() }
|
||||
}
|
||||
|
||||
pub fn send(&mut self, t: T) -> bool {
|
||||
@ -438,8 +438,7 @@ impl<T: Send> Packet<T> {
|
||||
// about looking at and dealing with to_wake. Once we have acquired the
|
||||
// lock, we are guaranteed that inherit_blocker is done.
|
||||
unsafe {
|
||||
self.select_lock.lock();
|
||||
self.select_lock.unlock();
|
||||
let _guard = self.select_lock.lock();
|
||||
}
|
||||
|
||||
// Like the stream implementation, we want to make sure that the count
|
||||
|
@ -44,7 +44,6 @@ use ptr;
|
||||
use str;
|
||||
use str::{Str, StrSlice};
|
||||
use fmt;
|
||||
use unstable::finally::Finally;
|
||||
use sync::atomics::{AtomicInt, INIT_ATOMIC_INT, SeqCst};
|
||||
use path::{Path, GenericPath};
|
||||
use iter::Iterator;
|
||||
@ -146,15 +145,12 @@ Serialize access through a global lock.
|
||||
*/
|
||||
fn with_env_lock<T>(f: || -> T) -> T {
|
||||
use unstable::mutex::{Mutex, MUTEX_INIT};
|
||||
use unstable::finally::Finally;
|
||||
|
||||
static mut lock: Mutex = MUTEX_INIT;
|
||||
|
||||
unsafe {
|
||||
return (|| {
|
||||
lock.lock();
|
||||
f()
|
||||
}).finally(|| lock.unlock());
|
||||
let _guard = lock.lock();
|
||||
f()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -68,7 +68,6 @@ mod imp {
|
||||
use option::{Option, Some, None};
|
||||
use ptr::RawPtr;
|
||||
use iter::Iterator;
|
||||
use unstable::finally::Finally;
|
||||
use unstable::mutex::{Mutex, MUTEX_INIT};
|
||||
use mem;
|
||||
|
||||
@ -111,16 +110,10 @@ mod imp {
|
||||
}
|
||||
|
||||
fn with_lock<T>(f: || -> T) -> T {
|
||||
(|| {
|
||||
unsafe {
|
||||
lock.lock();
|
||||
f()
|
||||
}
|
||||
}).finally(|| {
|
||||
unsafe {
|
||||
lock.unlock();
|
||||
}
|
||||
})
|
||||
unsafe {
|
||||
let _guard = lock.lock();
|
||||
f()
|
||||
}
|
||||
}
|
||||
|
||||
fn get_global_ptr() -> *mut Option<~~[~[u8]]> {
|
||||
|
@ -157,7 +157,7 @@ pub mod dl {
|
||||
unsafe {
|
||||
// dlerror isn't thread safe, so we need to lock around this entire
|
||||
// sequence
|
||||
lock.lock();
|
||||
let _guard = lock.lock();
|
||||
let _old_error = dlerror();
|
||||
|
||||
let result = f();
|
||||
@ -168,7 +168,7 @@ pub mod dl {
|
||||
} else {
|
||||
Err(str::raw::from_c_str(last_error))
|
||||
};
|
||||
lock.unlock();
|
||||
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
@ -47,10 +47,24 @@
|
||||
|
||||
#[allow(non_camel_case_types)];
|
||||
|
||||
use option::{Option, None, Some};
|
||||
use ops::Drop;
|
||||
|
||||
pub struct Mutex {
|
||||
priv inner: imp::Mutex,
|
||||
}
|
||||
|
||||
/// Automatically unlocks the mutex that it was created from on
|
||||
/// destruction.
|
||||
///
|
||||
/// Using this makes lock-based code resilient to unwinding/task
|
||||
/// failure, because the lock will be automatically unlocked even
|
||||
/// then.
|
||||
#[must_use]
|
||||
pub struct LockGuard<'a> {
|
||||
priv lock: &'a mut Mutex
|
||||
}
|
||||
|
||||
pub static MUTEX_INIT: Mutex = Mutex {
|
||||
inner: imp::MUTEX_INIT,
|
||||
};
|
||||
@ -63,23 +77,62 @@ impl Mutex {
|
||||
|
||||
/// Acquires this lock. This assumes that the current thread does not
|
||||
/// already hold the lock.
|
||||
pub unsafe fn lock(&mut self) { self.inner.lock() }
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// use std::unstable::mutex::Mutex;
|
||||
/// unsafe {
|
||||
/// let mut lock = Mutex::new();
|
||||
///
|
||||
/// {
|
||||
/// 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 whether the lock was
|
||||
/// acquired or not
|
||||
pub unsafe fn trylock(&mut self) -> bool { self.inner.trylock() }
|
||||
LockGuard { lock: self }
|
||||
}
|
||||
|
||||
/// 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>> {
|
||||
if self.inner.trylock() {
|
||||
Some(LockGuard { lock: self })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Acquire the lock without creating a `LockGuard`.
|
||||
///
|
||||
/// Prefer using `.lock`.
|
||||
pub unsafe fn lock_noguard(&mut self) { self.inner.lock() }
|
||||
|
||||
/// 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()
|
||||
}
|
||||
|
||||
/// Unlocks the lock. This assumes that the current thread already holds the
|
||||
/// lock.
|
||||
pub unsafe fn unlock(&mut self) { self.inner.unlock() }
|
||||
pub unsafe fn unlock_noguard(&mut self) { self.inner.unlock() }
|
||||
|
||||
/// Block on the internal condition variable.
|
||||
///
|
||||
/// This function assumes that the lock is already held
|
||||
pub unsafe fn wait(&mut self) { self.inner.wait() }
|
||||
/// 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() }
|
||||
|
||||
/// Signals a thread in `wait` to wake up
|
||||
pub unsafe fn signal(&mut self) { self.inner.signal() }
|
||||
pub unsafe fn signal_noguard(&mut self) { self.inner.signal() }
|
||||
|
||||
/// This function is especially unsafe because there are no guarantees made
|
||||
/// that no other thread is currently holding the lock or waiting on the
|
||||
@ -87,6 +140,25 @@ impl Mutex {
|
||||
pub unsafe fn destroy(&mut self) { self.inner.destroy() }
|
||||
}
|
||||
|
||||
impl<'a> LockGuard<'a> {
|
||||
/// Block on the internal condition variable.
|
||||
pub unsafe fn wait(&mut self) {
|
||||
self.lock.wait_noguard()
|
||||
}
|
||||
|
||||
/// Signals a thread in `wait` to wake up.
|
||||
pub unsafe fn signal(&mut self) {
|
||||
self.lock.signal_noguard()
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe_destructor]
|
||||
impl<'a> Drop for LockGuard<'a> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {self.lock.unlock_noguard()}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
mod imp {
|
||||
use libc;
|
||||
@ -382,6 +454,7 @@ mod imp {
|
||||
mod test {
|
||||
use prelude::*;
|
||||
|
||||
use mem::drop;
|
||||
use super::{Mutex, MUTEX_INIT};
|
||||
use rt::thread::Thread;
|
||||
|
||||
@ -389,8 +462,7 @@ mod test {
|
||||
fn somke_lock() {
|
||||
static mut lock: Mutex = MUTEX_INIT;
|
||||
unsafe {
|
||||
lock.lock();
|
||||
lock.unlock();
|
||||
let _guard = lock.lock();
|
||||
}
|
||||
}
|
||||
|
||||
@ -398,14 +470,14 @@ mod test {
|
||||
fn somke_cond() {
|
||||
static mut lock: Mutex = MUTEX_INIT;
|
||||
unsafe {
|
||||
lock.lock();
|
||||
let mut guard = lock.lock();
|
||||
let t = Thread::start(proc() {
|
||||
lock.lock();
|
||||
lock.signal();
|
||||
lock.unlock();
|
||||
let mut guard = lock.lock();
|
||||
guard.signal();
|
||||
});
|
||||
lock.wait();
|
||||
lock.unlock();
|
||||
guard.wait();
|
||||
drop(guard);
|
||||
|
||||
t.join();
|
||||
}
|
||||
}
|
||||
|
@ -11,16 +11,16 @@
|
||||
use clone::Clone;
|
||||
use kinds::Send;
|
||||
use ops::Drop;
|
||||
use option::{Option,Some,None};
|
||||
use option::Option;
|
||||
use sync::arc::UnsafeArc;
|
||||
use unstable::mutex::Mutex;
|
||||
use unstable::mutex::{Mutex, LockGuard};
|
||||
|
||||
pub struct LittleLock {
|
||||
priv l: Mutex,
|
||||
}
|
||||
|
||||
pub struct LittleGuard<'a> {
|
||||
priv l: &'a mut Mutex,
|
||||
priv l: LockGuard<'a>
|
||||
}
|
||||
|
||||
impl Drop for LittleLock {
|
||||
@ -29,33 +29,21 @@ impl Drop for LittleLock {
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe_destructor]
|
||||
impl<'a> Drop for LittleGuard<'a> {
|
||||
fn drop(&mut self) {
|
||||
unsafe { self.l.unlock(); }
|
||||
}
|
||||
}
|
||||
|
||||
impl LittleLock {
|
||||
pub fn new() -> LittleLock {
|
||||
unsafe { LittleLock { l: Mutex::new() } }
|
||||
}
|
||||
|
||||
pub unsafe fn lock<'a>(&'a mut self) -> LittleGuard<'a> {
|
||||
self.l.lock();
|
||||
LittleGuard { l: &mut self.l }
|
||||
LittleGuard { l: self.l.lock() }
|
||||
}
|
||||
|
||||
pub unsafe fn try_lock<'a>(&'a mut self) -> Option<LittleGuard<'a>> {
|
||||
if self.l.trylock() {
|
||||
Some(LittleGuard { l: &mut self.l })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
self.l.trylock().map(|guard| LittleGuard { l: guard })
|
||||
}
|
||||
|
||||
pub unsafe fn signal(&mut self) {
|
||||
self.l.signal();
|
||||
self.l.signal_noguard();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -288,11 +288,11 @@ impl StaticMutex {
|
||||
// `lock()` function on an OS mutex
|
||||
fn native_lock(&mut self, t: ~Task) {
|
||||
Local::put(t);
|
||||
unsafe { self.lock.lock(); }
|
||||
unsafe { self.lock.lock_noguard(); }
|
||||
}
|
||||
|
||||
fn native_unlock(&mut self) {
|
||||
unsafe { self.lock.unlock(); }
|
||||
unsafe { self.lock.unlock_noguard(); }
|
||||
}
|
||||
|
||||
fn green_lock(&mut self, t: ~Task) {
|
||||
|
Loading…
Reference in New Issue
Block a user