diff options
Diffstat (limited to 'src/libcore/unstable/mod.rs')
| -rw-r--r-- | src/libcore/unstable/mod.rs | 281 |
1 files changed, 7 insertions, 274 deletions
diff --git a/src/libcore/unstable/mod.rs b/src/libcore/unstable/mod.rs index ef7d70783c8..bef7a7f87d3 100644 --- a/src/libcore/unstable/mod.rs +++ b/src/libcore/unstable/mod.rs @@ -10,13 +10,10 @@ #[doc(hidden)]; -use cast; use libc; use comm::{GenericChan, GenericPort}; use prelude::*; use task; -use task::atomically; -use self::finally::Finally; pub mod at_exit; pub mod global; @@ -28,23 +25,7 @@ pub mod simd; pub mod extfmt; #[cfg(not(test))] pub mod lang; - -mod rustrt { - use unstable::{raw_thread, rust_little_lock}; - - pub extern { - pub unsafe fn rust_create_little_lock() -> rust_little_lock; - pub unsafe fn rust_destroy_little_lock(lock: rust_little_lock); - pub unsafe fn rust_lock_little_lock(lock: rust_little_lock); - pub unsafe fn rust_unlock_little_lock(lock: rust_little_lock); - - pub unsafe fn rust_raw_thread_start(f: &(&fn())) -> *raw_thread; - pub unsafe fn rust_raw_thread_join_delete(thread: *raw_thread); - } -} - -#[allow(non_camel_case_types)] // runtime type -pub type raw_thread = libc::c_void; +pub mod sync; /** @@ -63,8 +44,8 @@ pub fn run_in_bare_thread(f: ~fn()) { let closure: &fn() = || { f() }; - let thread = rustrt::rust_raw_thread_start(&closure); - rustrt::rust_raw_thread_join_delete(thread); + let thread = rust_raw_thread_start(&closure); + rust_raw_thread_join_delete(thread); chan.send(()); } } @@ -88,258 +69,10 @@ fn test_run_in_bare_thread_exchange() { } } -fn compare_and_swap(address: &mut int, oldval: int, newval: int) -> bool { - unsafe { - let old = intrinsics::atomic_cxchg(address, oldval, newval); - old == oldval - } -} - -/**************************************************************************** - * Shared state & exclusive ARC - ****************************************************************************/ - -struct ArcData<T> { - count: libc::intptr_t, - // FIXME(#3224) should be able to make this non-option to save memory - data: Option<T>, -} - -struct ArcDestruct<T> { - data: *libc::c_void, -} - -#[unsafe_destructor] -impl<T> Drop for ArcDestruct<T>{ - fn finalize(&self) { - unsafe { - do task::unkillable { - let mut data: ~ArcData<T> = cast::transmute(self.data); - let new_count = - intrinsics::atomic_xsub(&mut data.count, 1) - 1; - assert!(new_count >= 0); - if new_count == 0 { - // drop glue takes over. - } else { - cast::forget(data); - } - } - } - } -} - -fn ArcDestruct<T>(data: *libc::c_void) -> ArcDestruct<T> { - ArcDestruct { - data: data - } -} - -/** - * COMPLETELY UNSAFE. Used as a primitive for the safe versions in std::arc. - * - * Data races between tasks can result in crashes and, with sufficient - * cleverness, arbitrary type coercion. - */ -pub type SharedMutableState<T> = ArcDestruct<T>; - -pub unsafe fn shared_mutable_state<T:Owned>(data: T) -> - SharedMutableState<T> { - let data = ~ArcData { count: 1, data: Some(data) }; - let ptr = cast::transmute(data); - ArcDestruct(ptr) -} - -#[inline(always)] -pub unsafe fn get_shared_mutable_state<T:Owned>( - rc: *SharedMutableState<T>) -> *mut T -{ - let ptr: ~ArcData<T> = cast::transmute((*rc).data); - assert!(ptr.count > 0); - let r = cast::transmute(ptr.data.get_ref()); - cast::forget(ptr); - return r; -} -#[inline(always)] -pub unsafe fn get_shared_immutable_state<'a,T:Owned>( - rc: &'a SharedMutableState<T>) -> &'a T { - let ptr: ~ArcData<T> = cast::transmute((*rc).data); - assert!(ptr.count > 0); - // Cast us back into the correct region - let r = cast::transmute_region(ptr.data.get_ref()); - cast::forget(ptr); - return r; -} - -pub unsafe fn clone_shared_mutable_state<T:Owned>(rc: &SharedMutableState<T>) - -> SharedMutableState<T> { - let mut ptr: ~ArcData<T> = cast::transmute((*rc).data); - let new_count = intrinsics::atomic_xadd(&mut ptr.count, 1) + 1; - assert!(new_count >= 2); - cast::forget(ptr); - ArcDestruct((*rc).data) -} - -impl<T:Owned> Clone for SharedMutableState<T> { - fn clone(&self) -> SharedMutableState<T> { - unsafe { - clone_shared_mutable_state(self) - } - } -} - -/****************************************************************************/ - #[allow(non_camel_case_types)] // runtime type -pub type rust_little_lock = *libc::c_void; - -struct LittleLock { - l: rust_little_lock, -} - -impl Drop for LittleLock { - fn finalize(&self) { - unsafe { - rustrt::rust_destroy_little_lock(self.l); - } - } -} - -fn LittleLock() -> LittleLock { - unsafe { - LittleLock { - l: rustrt::rust_create_little_lock() - } - } -} - -pub impl LittleLock { - #[inline(always)] - unsafe fn lock<T>(&self, f: &fn() -> T) -> T { - do atomically { - rustrt::rust_lock_little_lock(self.l); - do (|| { - f() - }).finally { - rustrt::rust_unlock_little_lock(self.l); - } - } - } -} - -struct ExData<T> { - lock: LittleLock, - failed: bool, - data: T, -} - -/** - * An arc over mutable data that is protected by a lock. For library use only. - */ -pub struct Exclusive<T> { - x: SharedMutableState<ExData<T>> -} - -pub fn exclusive<T:Owned>(user_data: T) -> Exclusive<T> { - let data = ExData { - lock: LittleLock(), - failed: false, - data: user_data - }; - Exclusive { - x: unsafe { - shared_mutable_state(data) - } - } -} - -impl<T:Owned> Clone for Exclusive<T> { - // Duplicate an exclusive ARC, as std::arc::clone. - fn clone(&self) -> Exclusive<T> { - Exclusive { x: unsafe { clone_shared_mutable_state(&self.x) } } - } -} - -pub impl<T:Owned> Exclusive<T> { - // Exactly like std::arc::mutex_arc,access(), but with the little_lock - // instead of a proper mutex. Same reason for being unsafe. - // - // Currently, scheduling operations (i.e., yielding, receiving on a pipe, - // accessing the provided condition variable) are prohibited while inside - // the exclusive. Supporting that is a work in progress. - #[inline(always)] - unsafe fn with<U>(&self, f: &fn(x: &mut T) -> U) -> U { - let rec = get_shared_mutable_state(&self.x); - do (*rec).lock.lock { - if (*rec).failed { - fail!( - ~"Poisoned exclusive - another task failed inside!"); - } - (*rec).failed = true; - let result = f(&mut (*rec).data); - (*rec).failed = false; - result - } - } - - #[inline(always)] - unsafe fn with_imm<U>(&self, f: &fn(x: &T) -> U) -> U { - do self.with |x| { - f(cast::transmute_immut(x)) - } - } -} - -#[cfg(test)] -mod tests { - use comm; - use super::exclusive; - use task; - use uint; - - #[test] - fn exclusive_arc() { - let mut futures = ~[]; - - let num_tasks = 10; - let count = 10; - - let total = exclusive(~0); - - for uint::range(0, num_tasks) |_i| { - let total = total.clone(); - let (port, chan) = comm::stream(); - futures.push(port); - - do task::spawn || { - for uint::range(0, count) |_i| { - do total.with |count| { - **count += 1; - } - } - chan.send(()); - } - }; - - for futures.each |f| { f.recv() } - - do total.with |total| { - assert!(**total == num_tasks * count) - }; - } +pub type raw_thread = libc::c_void; - #[test] #[should_fail] #[ignore(cfg(windows))] - fn exclusive_poison() { - // Tests that if one task fails inside of an exclusive, subsequent - // accesses will also fail. - let x = exclusive(1); - let x2 = x.clone(); - do task::try || { - do x2.with |one| { - assert!(*one == 2); - } - }; - do x.with |one| { - assert!(*one == 1); - } - } +extern { + fn rust_raw_thread_start(f: &(&fn())) -> *raw_thread; + fn rust_raw_thread_join_delete(thread: *raw_thread); } |
