diff options
| author | Patrick Walton <pcwalton@mimiga.net> | 2013-12-05 17:34:37 -0800 |
|---|---|---|
| committer | Patrick Walton <pcwalton@mimiga.net> | 2013-12-10 15:13:13 -0800 |
| commit | 89e1db3d6ce37946afd7115dfcce510261537a85 (patch) | |
| tree | 4ae3327b50138f2f416165a99576372676c22643 /src/libstd/unstable | |
| parent | 6bd80f74505a3eb7c44753c69cbe253ff566d5c1 (diff) | |
| download | rust-89e1db3d6ce37946afd7115dfcce510261537a85.tar.gz rust-89e1db3d6ce37946afd7115dfcce510261537a85.zip | |
libstd: Change `atomically` to use RAII.
Diffstat (limited to 'src/libstd/unstable')
| -rw-r--r-- | src/libstd/unstable/dynamic_lib.rs | 54 | ||||
| -rw-r--r-- | src/libstd/unstable/sync.rs | 60 |
2 files changed, 71 insertions, 43 deletions
diff --git a/src/libstd/unstable/dynamic_lib.rs b/src/libstd/unstable/dynamic_lib.rs index 2a6e40dc3a0..42a696eaf7e 100644 --- a/src/libstd/unstable/dynamic_lib.rs +++ b/src/libstd/unstable/dynamic_lib.rs @@ -140,7 +140,7 @@ pub mod dl { use path; use ptr; use str; - use unstable::sync::atomically; + use unstable::sync::atomic; use result::*; pub unsafe fn open_external(filename: &path::Path) -> *libc::c_void { @@ -158,25 +158,24 @@ pub mod dl { static mut lock: Mutex = MUTEX_INIT; unsafe { // dlerror isn't thread safe, so we need to lock around this entire - // sequence. `atomically` asserts that we don't do anything that + // sequence. `atomic` asserts that we don't do anything that // would cause this task to be descheduled, which could deadlock // the scheduler if it happens while the lock is held. // FIXME #9105 use a Rust mutex instead of C++ mutexes. - atomically(|| { - lock.lock(); - let _old_error = dlerror(); - - let result = f(); - - let last_error = dlerror(); - let ret = if ptr::null() == last_error { - Ok(result) - } else { - Err(str::raw::from_c_str(last_error)) - }; - lock.unlock(); - ret - }) + let _guard = atomic(); + lock.lock(); + let _old_error = dlerror(); + + let result = f(); + + let last_error = dlerror(); + let ret = if ptr::null() == last_error { + Ok(result) + } else { + Err(str::raw::from_c_str(last_error)) + }; + lock.unlock(); + ret } } @@ -209,7 +208,7 @@ pub mod dl { use libc; use path; use ptr; - use unstable::sync::atomically; + use unstable::sync::atomic; use result::*; pub unsafe fn open_external(filename: &path::Path) -> *libc::c_void { @@ -226,18 +225,17 @@ pub mod dl { pub fn check_for_errors_in<T>(f: || -> T) -> Result<T, ~str> { unsafe { - atomically(|| { - SetLastError(0); + let _guard = atomic(); + SetLastError(0); - let result = f(); + let result = f(); - let error = os::errno(); - if 0 == error { - Ok(result) - } else { - Err(format!("Error code {}", error)) - } - }) + let error = os::errno(); + if 0 == error { + Ok(result) + } else { + Err(format!("Error code {}", error)) + } } } diff --git a/src/libstd/unstable/sync.rs b/src/libstd/unstable/sync.rs index b66e551c193..2dd5515bdbc 100644 --- a/src/libstd/unstable/sync.rs +++ b/src/libstd/unstable/sync.rs @@ -14,7 +14,6 @@ use ptr; use option::{Option,Some,None}; use task; use unstable::atomics::{AtomicOption,AtomicUint,Acquire,Release,Relaxed,SeqCst}; -use unstable::finally::Finally; use unstable::mutex::Mutex; use ops::Drop; use clone::Clone; @@ -295,17 +294,44 @@ impl<T> Drop for UnsafeArc<T>{ /****************************************************************************/ +pub struct AtomicGuard { + on: bool, +} + +impl Drop for AtomicGuard { + fn drop(&mut self) { + use rt::task::{Task, GreenTask, SchedTask}; + use rt::local::Local; + + if self.on { + unsafe { + let task_opt: Option<*mut Task> = Local::try_unsafe_borrow(); + match task_opt { + Some(t) => { + match (*t).task_type { + GreenTask(_) => (*t).death.allow_deschedule(), + SchedTask => {} + } + } + None => {} + } + } + } + } +} + /** - * Enables a runtime assertion that no operation in the argument closure shall - * use scheduler operations (deschedule, recv, spawn, etc). This is for use with - * pthread mutexes, which may block the entire scheduler thread, rather than - * just one task, and is hence prone to deadlocks if mixed with descheduling. + * Enables a runtime assertion that no operation while the returned guard is + * live uses scheduler operations (deschedule, recv, spawn, etc). This is for + * use with pthread mutexes, which may block the entire scheduler thread, + * rather than just one task, and is hence prone to deadlocks if mixed with + * descheduling. * * NOTE: THIS DOES NOT PROVIDE LOCKING, or any sort of critical-section * synchronization whatsoever. It only makes sense to use for CPU-local issues. */ // FIXME(#8140) should not be pub -pub unsafe fn atomically<U>(f: || -> U) -> U { +pub unsafe fn atomic() -> AtomicGuard { use rt::task::{Task, GreenTask, SchedTask}; use rt::local::Local; @@ -314,15 +340,19 @@ pub unsafe fn atomically<U>(f: || -> U) -> U { Some(t) => { match (*t).task_type { GreenTask(_) => { - (|| { - (*t).death.inhibit_deschedule(); - f() - }).finally(|| (*t).death.allow_deschedule()) + (*t).death.inhibit_deschedule(); + return AtomicGuard { + on: true, + }; } - SchedTask => f() + SchedTask => {} } } - None => f() + None => {} + } + + AtomicGuard { + on: false, } } @@ -481,7 +511,7 @@ mod tests { use comm; use option::*; use prelude::*; - use super::{Exclusive, UnsafeArc, atomically}; + use super::{Exclusive, UnsafeArc, atomic}; use task; use mem::size_of; @@ -493,10 +523,10 @@ mod tests { } #[test] - fn test_atomically() { + fn test_atomic() { // NB. The whole runtime will abort on an 'atomic-sleep' violation, // so we can't really test for the converse behaviour. - unsafe { atomically(|| ()) } task::deschedule(); // oughtn't fail + unsafe { let _ = atomic(); } // oughtn't fail } #[test] |
