diff options
| author | bors <bors@rust-lang.org> | 2014-12-27 13:11:48 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2014-12-27 13:11:48 +0000 |
| commit | 4a4c89c7a4a763c253a97ff04647f52aca6a5490 (patch) | |
| tree | e7d313c7ebc0418284ea65089db287cca633bc99 /src/libstd | |
| parent | 9be54be15b4b4ba5c1b22d958d7619a5154ab469 (diff) | |
| parent | 1a73ccc8db0a10e82632808e058645f2d6fa0095 (diff) | |
| download | rust-4a4c89c7a4a763c253a97ff04647f52aca6a5490.tar.gz rust-4a4c89c7a4a763c253a97ff04647f52aca6a5490.zip | |
auto merge of #20119 : FlaPer87/rust/oibit-send-and-friends, r=nikomatsakis
More work on opt-in built in traits. `Send` and `Sync` are not opt-in, `OwnedPtr` renamed to `UniquePtr` and the `Send` and `Sync` traits are now unsafe. NOTE: This likely needs to be rebased on top of the yet-to-land snapshot. r? @nikomatsakis cc #13231
Diffstat (limited to 'src/libstd')
30 files changed, 249 insertions, 65 deletions
diff --git a/src/libstd/c_str.rs b/src/libstd/c_str.rs index fb369924c64..ffe19203769 100644 --- a/src/libstd/c_str.rs +++ b/src/libstd/c_str.rs @@ -72,13 +72,12 @@ use libc; use fmt; use hash; -use kinds::marker; use mem; use ptr; use slice::{mod, ImmutableIntSlice}; use str; use string::String; - +use core::kinds::marker; /// The representation of a C String. /// @@ -90,6 +89,9 @@ pub struct CString { owns_buffer_: bool, } +unsafe impl Send for CString { } +unsafe impl Sync for CString { } + impl Clone for CString { /// Clone this CString into a new, uniquely owned CString. For safety /// reasons, this is always a deep clone with the memory allocated diff --git a/src/libstd/c_vec.rs b/src/libstd/c_vec.rs index 44e7291150e..f4338815f75 100644 --- a/src/libstd/c_vec.rs +++ b/src/libstd/c_vec.rs @@ -180,12 +180,12 @@ mod tests { fn malloc(n: uint) -> CVec<u8> { unsafe { - let mem = libc::malloc(n as libc::size_t); - if mem.is_null() { ::alloc::oom() } + let mem = ptr::Unique(libc::malloc(n as libc::size_t)); + if mem.0.is_null() { ::alloc::oom() } - CVec::new_with_dtor(mem as *mut u8, + CVec::new_with_dtor(mem.0 as *mut u8, n, - move|| { libc::free(mem as *mut libc::c_void); }) + move|| { libc::free(mem.0 as *mut libc::c_void); }) } } diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 8f2152c5a9d..3ae3a8ffbad 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -23,7 +23,7 @@ use num::{Int, UnsignedInt}; use ops::{Deref, DerefMut, Drop}; use option::Option; use option::Option::{Some, None}; -use ptr::{RawPtr, copy_nonoverlapping_memory, zero_memory}; +use ptr::{Unique, RawPtr, copy_nonoverlapping_memory, zero_memory}; use ptr; use rt::heap::{allocate, deallocate}; @@ -69,7 +69,7 @@ const EMPTY_BUCKET: u64 = 0u64; pub struct RawTable<K, V> { capacity: uint, size: uint, - hashes: *mut u64, + hashes: Unique<u64>, // Because K/V do not appear directly in any of the types in the struct, // inform rustc that in fact instances of K and V are reachable from here. marker: marker::CovariantType<(K,V)>, @@ -563,7 +563,7 @@ impl<K, V> RawTable<K, V> { return RawTable { size: 0, capacity: 0, - hashes: 0 as *mut u64, + hashes: Unique::null(), marker: marker::CovariantType, }; } @@ -602,7 +602,7 @@ impl<K, V> RawTable<K, V> { RawTable { capacity: capacity, size: 0, - hashes: hashes, + hashes: Unique(hashes), marker: marker::CovariantType, } } @@ -611,14 +611,14 @@ impl<K, V> RawTable<K, V> { let hashes_size = self.capacity * size_of::<u64>(); let keys_size = self.capacity * size_of::<K>(); - let buffer = self.hashes as *mut u8; + let buffer = self.hashes.0 as *mut u8; let (keys_offset, vals_offset) = calculate_offsets(hashes_size, keys_size, min_align_of::<K>(), min_align_of::<V>()); unsafe { RawBucket { - hash: self.hashes, + hash: self.hashes.0, key: buffer.offset(keys_offset as int) as *mut K, val: buffer.offset(vals_offset as int) as *mut V } @@ -631,7 +631,7 @@ impl<K, V> RawTable<K, V> { pub fn new(capacity: uint) -> RawTable<K, V> { unsafe { let ret = RawTable::new_uninitialized(capacity); - zero_memory(ret.hashes, capacity); + zero_memory(ret.hashes.0, capacity); ret } } @@ -651,7 +651,7 @@ impl<K, V> RawTable<K, V> { RawBuckets { raw: self.first_bucket_raw(), hashes_end: unsafe { - self.hashes.offset(self.capacity as int) + self.hashes.0.offset(self.capacity as int) }, marker: marker::ContravariantLifetime, } @@ -916,7 +916,7 @@ impl<K: Clone, V: Clone> Clone for RawTable<K, V> { #[unsafe_destructor] impl<K, V> Drop for RawTable<K, V> { fn drop(&mut self) { - if self.hashes.is_null() { + if self.hashes.0.is_null() { return; } // This is done in reverse because we've likely partially taken @@ -936,7 +936,7 @@ impl<K, V> Drop for RawTable<K, V> { vals_size, min_align_of::<V>()); unsafe { - deallocate(self.hashes as *mut u8, size, align); + deallocate(self.hashes.0 as *mut u8, size, align); // Remember how everything was allocated out of one buffer // during initialization? We only need one call to free here. } diff --git a/src/libstd/comm/blocking.rs b/src/libstd/comm/blocking.rs index c477acd70aa..412b7161305 100644 --- a/src/libstd/comm/blocking.rs +++ b/src/libstd/comm/blocking.rs @@ -13,6 +13,7 @@ use thread::Thread; use sync::atomic::{AtomicBool, INIT_ATOMIC_BOOL, Ordering}; use sync::Arc; +use kinds::{Sync, Send}; use kinds::marker::{NoSend, NoSync}; use mem; use clone::Clone; @@ -22,6 +23,9 @@ struct Inner { woken: AtomicBool, } +unsafe impl Send for Inner {} +unsafe impl Sync for Inner {} + #[deriving(Clone)] pub struct SignalToken { inner: Arc<Inner>, diff --git a/src/libstd/comm/mod.rs b/src/libstd/comm/mod.rs index d3bfaab83da..c85bea87218 100644 --- a/src/libstd/comm/mod.rs +++ b/src/libstd/comm/mod.rs @@ -319,6 +319,7 @@ pub use self::TrySendError::*; use self::Flavor::*; use alloc::arc::Arc; +use core::kinds; use core::kinds::marker; use core::mem; use core::cell::UnsafeCell; @@ -357,10 +358,12 @@ mod spsc_queue; #[unstable] pub struct Receiver<T> { inner: UnsafeCell<Flavor<T>>, - // can't share in an arc - _marker: marker::NoSync, } +// The receiver port can be sent from place to place, so long as it +// is not used to receive non-sendable things. +unsafe impl<T:Send> Send for Receiver<T> { } + /// An iterator over messages on a receiver, this iterator will block /// whenever `next` is called, waiting for a new message, and `None` will be /// returned when the corresponding channel has hung up. @@ -374,15 +377,17 @@ pub struct Messages<'a, T:'a> { #[unstable] pub struct Sender<T> { inner: UnsafeCell<Flavor<T>>, - // can't share in an arc - _marker: marker::NoSync, } +// The send port can be sent from place to place, so long as it +// is not used to send non-sendable things. +unsafe impl<T:Send> Send for Sender<T> { } + /// The sending-half of Rust's synchronous channel type. This half can only be /// owned by one task, but it can be cloned to send to other tasks. #[unstable = "this type may be renamed, but it will always exist"] pub struct SyncSender<T> { - inner: Arc<UnsafeCell<sync::Packet<T>>>, + inner: Arc<RacyCell<sync::Packet<T>>>, // can't share in an arc _marker: marker::NoSync, } @@ -418,10 +423,10 @@ pub enum TrySendError<T> { } enum Flavor<T> { - Oneshot(Arc<UnsafeCell<oneshot::Packet<T>>>), - Stream(Arc<UnsafeCell<stream::Packet<T>>>), - Shared(Arc<UnsafeCell<shared::Packet<T>>>), - Sync(Arc<UnsafeCell<sync::Packet<T>>>), + Oneshot(Arc<RacyCell<oneshot::Packet<T>>>), + Stream(Arc<RacyCell<stream::Packet<T>>>), + Shared(Arc<RacyCell<shared::Packet<T>>>), + Sync(Arc<RacyCell<sync::Packet<T>>>), } #[doc(hidden)] @@ -472,7 +477,7 @@ impl<T> UnsafeFlavor<T> for Receiver<T> { /// ``` #[unstable] pub fn channel<T: Send>() -> (Sender<T>, Receiver<T>) { - let a = Arc::new(UnsafeCell::new(oneshot::Packet::new())); + let a = Arc::new(RacyCell::new(oneshot::Packet::new())); (Sender::new(Oneshot(a.clone())), Receiver::new(Oneshot(a))) } @@ -512,7 +517,7 @@ pub fn channel<T: Send>() -> (Sender<T>, Receiver<T>) { #[unstable = "this function may be renamed to more accurately reflect the type \ of channel that is is creating"] pub fn sync_channel<T: Send>(bound: uint) -> (SyncSender<T>, Receiver<T>) { - let a = Arc::new(UnsafeCell::new(sync::Packet::new(bound))); + let a = Arc::new(RacyCell::new(sync::Packet::new(bound))); (SyncSender::new(a.clone()), Receiver::new(Sync(a))) } @@ -524,7 +529,6 @@ impl<T: Send> Sender<T> { fn new(inner: Flavor<T>) -> Sender<T> { Sender { inner: UnsafeCell::new(inner), - _marker: marker::NoSync, } } @@ -594,7 +598,8 @@ impl<T: Send> Sender<T> { if !(*p).sent() { return (*p).send(t); } else { - let a = Arc::new(UnsafeCell::new(stream::Packet::new())); + let a = + Arc::new(RacyCell::new(stream::Packet::new())); match (*p).upgrade(Receiver::new(Stream(a.clone()))) { oneshot::UpSuccess => { let ret = (*a.get()).send(t); @@ -631,7 +636,7 @@ impl<T: Send> Clone for Sender<T> { fn clone(&self) -> Sender<T> { let (packet, sleeper, guard) = match *unsafe { self.inner() } { Oneshot(ref p) => { - let a = Arc::new(UnsafeCell::new(shared::Packet::new())); + let a = Arc::new(RacyCell::new(shared::Packet::new())); unsafe { let guard = (*a.get()).postinit_lock(); match (*p.get()).upgrade(Receiver::new(Shared(a.clone()))) { @@ -642,7 +647,7 @@ impl<T: Send> Clone for Sender<T> { } } Stream(ref p) => { - let a = Arc::new(UnsafeCell::new(shared::Packet::new())); + let a = Arc::new(RacyCell::new(shared::Packet::new())); unsafe { let guard = (*a.get()).postinit_lock(); match (*p.get()).upgrade(Receiver::new(Shared(a.clone()))) { @@ -686,7 +691,7 @@ impl<T: Send> Drop for Sender<T> { //////////////////////////////////////////////////////////////////////////////// impl<T: Send> SyncSender<T> { - fn new(inner: Arc<UnsafeCell<sync::Packet<T>>>) -> SyncSender<T> { + fn new(inner: Arc<RacyCell<sync::Packet<T>>>) -> SyncSender<T> { SyncSender { inner: inner, _marker: marker::NoSync } } @@ -775,7 +780,7 @@ impl<T: Send> Drop for SyncSender<T> { impl<T: Send> Receiver<T> { fn new(inner: Flavor<T>) -> Receiver<T> { - Receiver { inner: UnsafeCell::new(inner), _marker: marker::NoSync } + Receiver { inner: UnsafeCell::new(inner) } } /// Blocks waiting for a value on this receiver @@ -1018,6 +1023,27 @@ impl<T: Send> Drop for Receiver<T> { } } +/// A version of `UnsafeCell` intended for use in concurrent data +/// structures (for example, you might put it in an `Arc`). +struct RacyCell<T>(pub UnsafeCell<T>); + +impl<T> RacyCell<T> { + + fn new(value: T) -> RacyCell<T> { + RacyCell(UnsafeCell { value: value }) + } + + unsafe fn get(&self) -> *mut T { + self.0.get() + } + +} + +unsafe impl<T:Send> Send for RacyCell<T> { } + +unsafe impl<T> kinds::Sync for RacyCell<T> { } // Oh dear + + #[cfg(test)] mod test { use super::*; diff --git a/src/libstd/comm/mpsc_queue.rs b/src/libstd/comm/mpsc_queue.rs index db4e3eac449..cddef236664 100644 --- a/src/libstd/comm/mpsc_queue.rs +++ b/src/libstd/comm/mpsc_queue.rs @@ -76,6 +76,9 @@ pub struct Queue<T> { tail: UnsafeCell<*mut Node<T>>, } +unsafe impl<T:Send> Send for Queue<T> { } +unsafe impl<T:Send> Sync for Queue<T> { } + impl<T> Node<T> { unsafe fn new(v: Option<T>) -> *mut Node<T> { mem::transmute(box Node { diff --git a/src/libstd/comm/spsc_queue.rs b/src/libstd/comm/spsc_queue.rs index db8fff772a4..becb78063ae 100644 --- a/src/libstd/comm/spsc_queue.rs +++ b/src/libstd/comm/spsc_queue.rs @@ -73,6 +73,10 @@ pub struct Queue<T> { cache_subtractions: AtomicUint, } +unsafe impl<T: Send> Send for Queue<T> { } + +unsafe impl<T: Send> Sync for Queue<T> { } + impl<T: Send> Node<T> { fn new() -> *mut Node<T> { unsafe { diff --git a/src/libstd/comm/sync.rs b/src/libstd/comm/sync.rs index f75186e70e3..88338849965 100644 --- a/src/libstd/comm/sync.rs +++ b/src/libstd/comm/sync.rs @@ -53,6 +53,10 @@ pub struct Packet<T> { lock: Mutex<State<T>>, } +unsafe impl<T:Send> Send for Packet<T> { } + +unsafe impl<T:Send> Sync for Packet<T> { } + struct State<T> { disconnected: bool, // Is the channel disconnected yet? queue: Queue, // queue of senders waiting to send data @@ -69,6 +73,8 @@ struct State<T> { canceled: Option<&'static mut bool>, } +unsafe impl<T: Send> Send for State<T> {} + /// Possible flavors of threads who can be blocked on this channel. enum Blocker { BlockedSender(SignalToken), @@ -88,6 +94,8 @@ struct Node { next: *mut Node, } +unsafe impl Send for Node {} + /// A simple ring-buffer struct Buffer<T> { buf: Vec<Option<T>>, diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index 9d9e8827571..c26450310a9 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -22,6 +22,7 @@ use result::Result::{Ok, Err}; use slice::{SliceExt}; use slice; use vec::Vec; +use kinds::{Send,Sync}; /// Wraps a Reader and buffers input from it /// @@ -51,6 +52,11 @@ pub struct BufferedReader<R> { cap: uint, } + +unsafe impl<R: Send> Send for BufferedReader<R> {} +unsafe impl<R: Send+Sync> Sync for BufferedReader<R> {} + + impl<R: Reader> BufferedReader<R> { /// Creates a new `BufferedReader` with the specified buffer capacity pub fn with_capacity(cap: uint, inner: R) -> BufferedReader<R> { diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index 1c5ceaf2450..b7da57fed27 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -34,7 +34,7 @@ use failure::LOCAL_STDERR; use fmt; use io::{Reader, Writer, IoResult, IoError, OtherIoError, Buffer, standard_error, EndOfFile, LineBufferedWriter, BufferedReader}; -use kinds::Send; +use kinds::{Sync, Send}; use libc; use mem; use option::Option; @@ -98,26 +98,34 @@ thread_local! { } } +struct RaceBox(BufferedReader<StdReader>); + +unsafe impl Send for RaceBox {} +unsafe impl Sync for RaceBox {} + /// A synchronized wrapper around a buffered reader from stdin #[deriving(Clone)] pub struct StdinReader { - inner: Arc<Mutex<BufferedReader<StdReader>>>, + inner: Arc<Mutex<RaceBox>>, } +unsafe impl Send for StdinReader {} +unsafe impl Sync for StdinReader {} + /// A guard for exclusive access to `StdinReader`'s internal `BufferedReader`. pub struct StdinReaderGuard<'a> { - inner: MutexGuard<'a, BufferedReader<StdReader>>, + inner: MutexGuard<'a, RaceBox>, } impl<'a> Deref<BufferedReader<StdReader>> for StdinReaderGuard<'a> { fn deref(&self) -> &BufferedReader<StdReader> { - &*self.inner + &self.inner.0 } } impl<'a> DerefMut<BufferedReader<StdReader>> for StdinReaderGuard<'a> { fn deref_mut(&mut self) -> &mut BufferedReader<StdReader> { - &mut *self.inner + &mut self.inner.0 } } @@ -147,7 +155,7 @@ impl StdinReader { /// The read is performed atomically - concurrent read calls in other /// threads will not interleave with this one. pub fn read_line(&mut self) -> IoResult<String> { - self.inner.lock().read_line() + self.inner.lock().0.read_line() } /// Like `Buffer::read_until`. @@ -155,7 +163,7 @@ impl StdinReader { /// The read is performed atomically - concurrent read calls in other /// threads will not interleave with this one. pub fn read_until(&mut self, byte: u8) -> IoResult<Vec<u8>> { - self.inner.lock().read_until(byte) + self.inner.lock().0.read_until(byte) } /// Like `Buffer::read_char`. @@ -163,13 +171,13 @@ impl StdinReader { /// The read is performed atomically - concurrent read calls in other /// threads will not interleave with this one. pub fn read_char(&mut self) -> IoResult<char> { - self.inner.lock().read_char() + self.inner.lock().0.read_char() } } impl Reader for StdinReader { fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { - self.inner.lock().read(buf) + self.inner.lock().0.read(buf) } // We have to manually delegate all of these because the default impls call @@ -177,23 +185,23 @@ impl Reader for StdinReader { // incur the costs of repeated locking). fn read_at_least(&mut self, min: uint, buf: &mut [u8]) -> IoResult<uint> { - self.inner.lock().read_at_least(min, buf) + self.inner.lock().0.read_at_least(min, buf) } fn push_at_least(&mut self, min: uint, len: uint, buf: &mut Vec<u8>) -> IoResult<uint> { - self.inner.lock().push_at_least(min, len, buf) + self.inner.lock().0.push_at_least(min, len, buf) } fn read_to_end(&mut self) -> IoResult<Vec<u8>> { - self.inner.lock().read_to_end() + self.inner.lock().0.read_to_end() } fn read_le_uint_n(&mut self, nbytes: uint) -> IoResult<u64> { - self.inner.lock().read_le_uint_n(nbytes) + self.inner.lock().0.read_le_uint_n(nbytes) } fn read_be_uint_n(&mut self, nbytes: uint) -> IoResult<u64> { - self.inner.lock().read_be_uint_n(nbytes) + self.inner.lock().0.read_be_uint_n(nbytes) } } @@ -221,7 +229,7 @@ pub fn stdin() -> StdinReader { BufferedReader::new(stdin_raw()) }; let stdin = StdinReader { - inner: Arc::new(Mutex::new(stdin)) + inner: Arc::new(Mutex::new(RaceBox(stdin))) }; STDIN = mem::transmute(box stdin); @@ -426,6 +434,9 @@ pub struct StdWriter { inner: StdSource } +unsafe impl Send for StdWriter {} +unsafe impl Sync for StdWriter {} + impl StdWriter { /// Gets the size of this output window, if possible. This is typically used /// when the writer is attached to something like a terminal, this is used diff --git a/src/libstd/rt/exclusive.rs b/src/libstd/rt/exclusive.rs index 1d3082d1b4c..88bdb29caec 100644 --- a/src/libstd/rt/exclusive.rs +++ b/src/libstd/rt/exclusive.rs @@ -26,6 +26,10 @@ pub struct Exclusive<T> { data: UnsafeCell<T>, } +unsafe impl<T:Send> Send for Exclusive<T> { } + +unsafe impl<T:Send> Sync for Exclusive<T> { } + /// An RAII guard returned via `lock` pub struct ExclusiveGuard<'a, T:'a> { // FIXME #12808: strange name to try to avoid interfering with diff --git a/src/libstd/sync/barrier.rs b/src/libstd/sync/barrier.rs index 6573d9273ce..6cdb199819a 100644 --- a/src/libstd/sync/barrier.rs +++ b/src/libstd/sync/barrier.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use kinds::{Send, Sync}; use sync::{Mutex, Condvar}; /// A barrier enables multiple tasks to synchronize the beginning @@ -35,12 +36,18 @@ pub struct Barrier { num_threads: uint, } +unsafe impl Send for Barrier {} +unsafe impl Sync for Barrier {} + // The inner state of a double barrier struct BarrierState { count: uint, generation_id: uint, } +unsafe impl Send for BarrierState {} +unsafe impl Sync for BarrierState {} + impl Barrier { /// Create a new barrier that can block a given number of threads. /// diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs index be27c06b83c..f1940bfd829 100644 --- a/src/libstd/sync/condvar.rs +++ b/src/libstd/sync/condvar.rs @@ -58,6 +58,9 @@ use time::Duration; /// ``` pub struct Condvar { inner: Box<StaticCondvar> } +unsafe impl Send for Condvar {} +unsafe impl Sync for Condvar {} + /// Statically allocated condition variables. /// /// This structure is identical to `Condvar` except that it is suitable for use @@ -75,6 +78,9 @@ pub struct StaticCondvar { mutex: AtomicUint, } +unsafe impl Send for StaticCondvar {} +unsafe impl Sync for StaticCondvar {} + /// Constant initializer for a statically allocated condition variable. pub const CONDVAR_INIT: StaticCondvar = StaticCondvar { inner: sys::CONDVAR_INIT, diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index 4829be569cc..4d2fbfc4055 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -73,6 +73,10 @@ pub struct Mutex<T> { data: UnsafeCell<T>, } +unsafe impl<T:Send> Send for Mutex<T> { } + +unsafe impl<T:Send> Sync for Mutex<T> { } + /// The static mutex type is provided to allow for static allocation of mutexes. /// /// Note that this is a separate type because using a Mutex correctly means that @@ -99,6 +103,8 @@ pub struct StaticMutex { poison: UnsafeCell<poison::Flag>, } +unsafe impl Sync for StaticMutex {} + /// An RAII implementation of a "scoped lock" of a mutex. When this structure is /// dropped (falls out of scope), the lock will be unlocked. /// @@ -278,6 +284,11 @@ mod test { use thread::Thread; use sync::{Arc, Mutex, StaticMutex, MUTEX_INIT, Condvar}; + struct Packet<T>(Arc<(Mutex<T>, Condvar)>); + + unsafe impl<T:'static+Send> Send for Packet<T> {} + unsafe impl<T> Sync for Packet<T> {} + #[test] fn smoke() { let m = Mutex::new(()); @@ -337,19 +348,19 @@ mod test { #[test] fn test_mutex_arc_condvar() { - let arc = Arc::new((Mutex::new(false), Condvar::new())); - let arc2 = arc.clone(); + let packet = Packet(Arc::new((Mutex::new(false), Condvar::new()))); + let packet2 = Packet(packet.0.clone()); let (tx, rx) = channel(); spawn(move|| { // wait until parent gets in rx.recv(); - let &(ref lock, ref cvar) = &*arc2; + let &(ref lock, ref cvar) = &*packet2.0; let mut lock = lock.lock(); *lock = true; cvar.notify_one(); }); - let &(ref lock, ref cvar) = &*arc; + let &(ref lock, ref cvar) = &*packet.0; let lock = lock.lock(); tx.send(()); assert!(!*lock); @@ -361,20 +372,20 @@ mod test { #[test] #[should_fail] fn test_arc_condvar_poison() { - let arc = Arc::new((Mutex::new(1i), Condvar::new())); - let arc2 = arc.clone(); + let packet = Packet(Arc::new((Mutex::new(1i), Condvar::new()))); + let packet2 = Packet(packet.0.clone()); let (tx, rx) = channel(); spawn(move|| { rx.recv(); - let &(ref lock, ref cvar) = &*arc2; + let &(ref lock, ref cvar) = &*packet2.0; let _g = lock.lock(); cvar.notify_one(); // Parent should fail when it wakes up. panic!(); }); - let &(ref lock, ref cvar) = &*arc; + let &(ref lock, ref cvar) = &*packet.0; let lock = lock.lock(); tx.send(()); while *lock == 1 { diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs index a43f822e351..4d9fbb59908 100644 --- a/src/libstd/sync/once.rs +++ b/src/libstd/sync/once.rs @@ -14,6 +14,7 @@ //! example use case would be for initializing an FFI library. use int; +use kinds::Sync; use mem::drop; use ops::FnOnce; use sync::atomic; @@ -41,6 +42,8 @@ pub struct Once { lock_cnt: atomic::AtomicInt, } +unsafe impl Sync for Once {} + /// Initialization value for static `Once` values. pub const ONCE_INIT: Once = Once { mutex: MUTEX_INIT, diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index 3f177a42f44..76d05d9bfd4 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -60,6 +60,9 @@ pub struct RWLock<T> { data: UnsafeCell<T>, } +unsafe impl<T:'static+Send> Send for RWLock<T> {} +unsafe impl<T> Sync for RWLock<T> {} + /// Structure representing a statically allocated RWLock. /// /// This structure is intended to be used inside of a `static` and will provide @@ -88,6 +91,9 @@ pub struct StaticRWLock { poison: UnsafeCell<poison::Flag>, } +unsafe impl Send for StaticRWLock {} +unsafe impl Sync for StaticRWLock {} + /// Constant initialization for a statically-initialized rwlock. pub const RWLOCK_INIT: StaticRWLock = StaticRWLock { inner: sys::RWLOCK_INIT, diff --git a/src/libstd/sys/common/helper_thread.rs b/src/libstd/sys/common/helper_thread.rs index 421778e2012..a629f035b07 100644 --- a/src/libstd/sys/common/helper_thread.rs +++ b/src/libstd/sys/common/helper_thread.rs @@ -59,6 +59,15 @@ pub struct Helper<M> { pub shutdown: UnsafeCell<bool>, } +unsafe impl<M:Send> Send for Helper<M> { } + +unsafe impl<M:Send> Sync for Helper<M> { } + +struct RaceBox(helper_signal::signal); + +unsafe impl Send for RaceBox {} +unsafe impl Sync for RaceBox {} + impl<M: Send> Helper<M> { /// Lazily boots a helper thread, becoming a no-op if the helper has already /// been spawned. @@ -81,9 +90,11 @@ impl<M: Send> Helper<M> { let (receive, send) = helper_signal::new(); *self.signal.get() = send as uint; + let receive = RaceBox(receive); + let t = f(); Thread::spawn(move |:| { - helper(receive, rx, t); + helper(receive.0, rx, t); let _g = self.lock.lock(); *self.shutdown.get() = true; self.cond.notify_one() diff --git a/src/libstd/sys/common/mutex.rs b/src/libstd/sys/common/mutex.rs index 1a8a92a105a..567c26956ef 100644 --- a/src/libstd/sys/common/mutex.rs +++ b/src/libstd/sys/common/mutex.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use kinds::Sync; use sys::mutex as imp; /// An OS-based mutual exclusion lock. @@ -17,6 +18,8 @@ use sys::mutex as imp; /// at the top level of the crate instead of this type. pub struct Mutex(imp::Mutex); +unsafe impl Sync for Mutex {} + /// Constant initializer for statically allocated mutexes. pub const MUTEX_INIT: Mutex = Mutex(imp::MUTEX_INIT); diff --git a/src/libstd/sys/unix/c.rs b/src/libstd/sys/unix/c.rs index e76f2a2b872..a4ebcbd25d0 100644 --- a/src/libstd/sys/unix/c.rs +++ b/src/libstd/sys/unix/c.rs @@ -162,6 +162,9 @@ mod signal { sa_restorer: *mut libc::c_void, } + unsafe impl ::kinds::Send for sigaction { } + unsafe impl ::kinds::Sync for sigaction { } + #[repr(C)] #[cfg(target_word_size = "32")] pub struct sigset_t { @@ -211,6 +214,9 @@ mod signal { sa_resv: [libc::c_int, ..1], } + impl ::kinds::Send for sigaction { } + impl ::kinds::Sync for sigaction { } + #[repr(C)] pub struct sigset_t { __val: [libc::c_ulong, ..32], diff --git a/src/libstd/sys/unix/mutex.rs b/src/libstd/sys/unix/mutex.rs index 2f01c53cb2c..81f8659d6ae 100644 --- a/src/libstd/sys/unix/mutex.rs +++ b/src/libstd/sys/unix/mutex.rs @@ -9,6 +9,7 @@ // except according to those terms. use cell::UnsafeCell; +use kinds::Sync; use sys::sync as ffi; use sys_common::mutex; @@ -23,6 +24,8 @@ pub const MUTEX_INIT: Mutex = Mutex { inner: UnsafeCell { value: ffi::PTHREAD_MUTEX_INITIALIZER }, }; +unsafe impl Sync for Mutex {} + impl Mutex { #[inline] pub unsafe fn new() -> Mutex { diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs index 348b7cfad33..f1b078b4e80 100644 --- a/src/libstd/sys/unix/pipe.rs +++ b/src/libstd/sys/unix/pipe.rs @@ -117,6 +117,9 @@ pub struct UnixStream { write_deadline: u64, } +unsafe impl Send for UnixStream {} +unsafe impl Sync for UnixStream {} + impl UnixStream { pub fn connect(addr: &CString, timeout: Option<u64>) -> IoResult<UnixStream> { @@ -215,6 +218,9 @@ pub struct UnixListener { path: CString, } +unsafe impl Send for UnixListener {} +unsafe impl Sync for UnixListener {} + impl UnixListener { pub fn bind(addr: &CString) -> IoResult<UnixListener> { bind(addr, libc::SOCK_STREAM).map(|fd| { @@ -259,6 +265,9 @@ struct AcceptorInner { closed: atomic::AtomicBool, } +unsafe impl Send for AcceptorInner {} +unsafe impl Sync for AcceptorInner {} + impl UnixAcceptor { pub fn fd(&self) -> fd_t { self.inner.listener.fd() } diff --git a/src/libstd/sys/unix/stack_overflow.rs b/src/libstd/sys/unix/stack_overflow.rs index 340f9514241..bcbbb8766b7 100644 --- a/src/libstd/sys/unix/stack_overflow.rs +++ b/src/libstd/sys/unix/stack_overflow.rs @@ -160,7 +160,7 @@ mod imp { pub static SIGSTKSZ: libc::size_t = 8192; - pub static SIG_DFL: sighandler_t = 0i as sighandler_t; + pub const SIG_DFL: sighandler_t = 0i as sighandler_t; // This definition is not as accurate as it could be, {si_addr} is // actually a giant union. Currently we're only interested in that field, diff --git a/src/libstd/sys/unix/tcp.rs b/src/libstd/sys/unix/tcp.rs index 5c99ad1e0ce..e2a78947e16 100644 --- a/src/libstd/sys/unix/tcp.rs +++ b/src/libstd/sys/unix/tcp.rs @@ -33,6 +33,8 @@ pub struct TcpListener { pub inner: FileDesc, } +unsafe impl Sync for TcpListener {} + impl TcpListener { pub fn bind(addr: ip::SocketAddr) -> IoResult<TcpListener> { let fd = try!(net::socket(addr, libc::SOCK_STREAM)); @@ -96,6 +98,8 @@ struct AcceptorInner { closed: atomic::AtomicBool, } +unsafe impl Sync for AcceptorInner {} + impl TcpAcceptor { pub fn fd(&self) -> sock_t { self.inner.listener.fd() } diff --git a/src/libstd/sys/windows/mutex.rs b/src/libstd/sys/windows/mutex.rs index ddd89070ed5..3ac7c09154e 100644 --- a/src/libstd/sys/windows/mutex.rs +++ b/src/libstd/sys/windows/mutex.rs @@ -22,6 +22,8 @@ pub struct Mutex { inner: atomic::AtomicUint } pub const MUTEX_INIT: Mutex = Mutex { inner: atomic::INIT_ATOMIC_UINT }; +unsafe impl Sync for Mutex {} + #[inline] pub unsafe fn raw(m: &Mutex) -> ffi::LPCRITICAL_SECTION { m.get() diff --git a/src/libstd/sys/windows/pipe.rs b/src/libstd/sys/windows/pipe.rs index bf658d0efd0..fc3640f2604 100644 --- a/src/libstd/sys/windows/pipe.rs +++ b/src/libstd/sys/windows/pipe.rs @@ -214,6 +214,9 @@ pub struct UnixStream { write_deadline: u64, } +unsafe impl Send for UnixStream {} +unsafe impl Sync for UnixStream {} + impl UnixStream { fn try_connect(p: *const u16) -> Option<libc::HANDLE> { // Note that most of this is lifted from the libuv implementation. @@ -559,6 +562,9 @@ pub struct UnixListener { name: CString, } +unsafe impl Send for UnixListener {} +unsafe impl Sync for UnixListener {} + impl UnixListener { pub fn bind(addr: &CString) -> IoResult<UnixListener> { // Although we technically don't need the pipe until much later, we @@ -603,11 +609,17 @@ pub struct UnixAcceptor { deadline: u64, } +unsafe impl Send for UnixAcceptor {} +unsafe impl Sync for UnixAcceptor {} + struct AcceptorState { abort: Event, closed: atomic::AtomicBool, } +unsafe impl Send for AcceptorState {} +unsafe impl Sync for AcceptorState {} + impl UnixAcceptor { pub fn accept(&mut self) -> IoResult<UnixStream> { // This function has some funky implementation details when working with diff --git a/src/libstd/sys/windows/tcp.rs b/src/libstd/sys/windows/tcp.rs index 505e6137bf9..513c1d38e36 100644 --- a/src/libstd/sys/windows/tcp.rs +++ b/src/libstd/sys/windows/tcp.rs @@ -24,6 +24,9 @@ pub use sys_common::net::TcpStream; pub struct Event(c::WSAEVENT); +unsafe impl Send for Event {} +unsafe impl Sync for Event {} + impl Event { pub fn new() -> IoResult<Event> { let event = unsafe { c::WSACreateEvent() }; @@ -49,6 +52,9 @@ impl Drop for Event { pub struct TcpListener { sock: sock_t } +unsafe impl Send for TcpListener {} +unsafe impl Sync for TcpListener {} + impl TcpListener { pub fn bind(addr: ip::SocketAddr) -> IoResult<TcpListener> { sys::init_net(); @@ -109,6 +115,9 @@ pub struct TcpAcceptor { deadline: u64, } +unsafe impl Send for TcpAcceptor {} +unsafe impl Sync for TcpAcceptor {} + struct AcceptorInner { listener: TcpListener, abort: Event, @@ -116,6 +125,9 @@ struct AcceptorInner { closed: atomic::AtomicBool, } +unsafe impl Send for AcceptorInner {} +unsafe impl Sync for AcceptorInner {} + impl TcpAcceptor { pub fn socket(&self) -> sock_t { self.inner.listener.socket() } diff --git a/src/libstd/sys/windows/timer.rs b/src/libstd/sys/windows/timer.rs index 7e4dd768aa9..874838950cd 100644 --- a/src/libstd/sys/windows/timer.rs +++ b/src/libstd/sys/windows/timer.rs @@ -48,6 +48,9 @@ pub enum Req { RemoveTimer(libc::HANDLE, Sender<()>), } +unsafe impl Send for Req {} + + fn helper(input: libc::HANDLE, messages: Receiver<Req>, _: ()) { let mut objs = vec![input]; let mut chans = vec![]; diff --git a/src/libstd/thread.rs b/src/libstd/thread.rs index 89773207347..56731bd7ec3 100644 --- a/src/libstd/thread.rs +++ b/src/libstd/thread.rs @@ -129,7 +129,7 @@ use borrow::IntoCow; use boxed::Box; use cell::UnsafeCell; use clone::Clone; -use kinds::Send; +use kinds::{Send, Sync}; use ops::{Drop, FnOnce}; use option::Option::{mod, Some, None}; use result::Result::{Err, Ok}; @@ -211,8 +211,8 @@ impl Builder { } fn spawn_inner<T: Send>(self, f: Thunk<(), T>) -> JoinGuard<T> { - let my_packet = Arc::new(UnsafeCell::new(None)); - let their_packet = my_packet.clone(); + let my_packet = Packet(Arc::new(UnsafeCell::new(None))); + let their_packet = Packet(my_packet.0.clone()); let Builder { name, stack_size, stdout, stderr } = self; @@ -266,7 +266,7 @@ impl Builder { } }; unsafe { - *their_packet.get() = Some(match (output, try_result) { + *their_packet.0.get() = Some(match (output, try_result) { (Some(data), Ok(_)) => Ok(data), (None, Err(cause)) => Err(cause), _ => unreachable!() @@ -289,12 +289,16 @@ struct Inner { cvar: Condvar, } +unsafe impl Sync for Inner {} + #[deriving(Clone)] /// A handle to a thread. pub struct Thread { inner: Arc<Inner>, } +unsafe impl Sync for Thread {} + impl Thread { // Used only internally to construct a thread object without spawning fn new(name: Option<String>) -> Thread { @@ -379,6 +383,11 @@ impl thread_info::NewThread for Thread { /// A thread that completes without panicking is considered to exit successfully. pub type Result<T> = ::result::Result<T, Box<Any + Send>>; +struct Packet<T>(Arc<UnsafeCell<Option<Result<T>>>>); + +unsafe impl<T:'static+Send> Send for Packet<T> {} +unsafe impl<T> Sync for Packet<T> {} + #[must_use] /// An RAII-style guard that will block until thread termination when dropped. /// @@ -387,9 +396,11 @@ pub struct JoinGuard<T> { native: imp::rust_thread, thread: Thread, joined: bool, - packet: Arc<UnsafeCell<Option<Result<T>>>>, + packet: Packet<T>, } +unsafe impl<T: Send> Sync for JoinGuard<T> {} + impl<T: Send> JoinGuard<T> { /// Extract a handle to the thread this guard will join on. pub fn thread(&self) -> &Thread { @@ -406,7 +417,7 @@ impl<T: Send> JoinGuard<T> { unsafe { imp::join(self.native) }; self.joined = true; unsafe { - (*self.packet.get()).take().unwrap() + (*self.packet.0.get()).take().unwrap() } } diff --git a/src/libstd/thread_local/mod.rs b/src/libstd/thread_local/mod.rs index 04718dcc6ae..242dceb4256 100644 --- a/src/libstd/thread_local/mod.rs +++ b/src/libstd/thread_local/mod.rs @@ -280,6 +280,8 @@ mod imp { pub dtor_running: UnsafeCell<bool>, // should be Cell } + unsafe impl<T> ::kinds::Sync for Key<T> { } + #[doc(hidden)] impl<T> Key<T> { pub unsafe fn get(&'static self) -> Option<&'static T> { @@ -410,6 +412,8 @@ mod imp { pub os: OsStaticKey, } + unsafe impl<T> ::kinds::Sync for Key<T> { } + struct Value<T: 'static> { key: &'static Key<T>, value: T, diff --git a/src/libstd/thread_local/scoped.rs b/src/libstd/thread_local/scoped.rs index 643a0f55e74..756c86c2115 100644 --- a/src/libstd/thread_local/scoped.rs +++ b/src/libstd/thread_local/scoped.rs @@ -198,10 +198,11 @@ impl<T> Key<T> { mod imp { use std::cell::UnsafeCell; - // FIXME: Should be a `Cell`, but that's not `Sync` #[doc(hidden)] pub struct KeyInner<T> { pub inner: UnsafeCell<*mut T> } + unsafe impl<T> ::kinds::Sync for KeyInner<T> { } + #[doc(hidden)] impl<T> KeyInner<T> { #[doc(hidden)] @@ -222,6 +223,8 @@ mod imp { pub marker: marker::InvariantType<T>, } + unsafe impl<T> ::kinds::Sync for KeyInner<T> { } + #[doc(hidden)] impl<T> KeyInner<T> { #[doc(hidden)] |
