about summary refs log tree commit diff
path: root/src/libstd/sync
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2014-12-19 08:28:52 +0000
committerbors <bors@rust-lang.org>2014-12-19 08:28:52 +0000
commit0efafac398ff7f28c5f0fe756c15b9008b3e0534 (patch)
tree2e8279b94829b65868049d2e3df0b9a6c3365a8f /src/libstd/sync
parent6bdce25e155d846bb9252fa4a18baef7e74cf8bf (diff)
parent903c5a8f69714382ec9fc22745f902c3e219cb68 (diff)
downloadrust-0efafac398ff7f28c5f0fe756c15b9008b3e0534.tar.gz
rust-0efafac398ff7f28c5f0fe756c15b9008b3e0534.zip
auto merge of #19654 : aturon/rust/merge-rt, r=alexcrichton
This PR substantially narrows the notion of a "runtime" in Rust, and allows calling into Rust code directly without any setup or teardown. 

After this PR, the basic "runtime support" in Rust will consist of:

* Unwinding and backtrace support
* Stack guards

Other support, such as helper threads for timers or the notion of a "current thread" are initialized automatically upon first use.

When using Rust in an embedded context, it should now be possible to call a Rust function directly as a C function with absolutely no setup, though in that case panics will cause the process to abort. In this regard, the C/Rust interface will look much like the C/C++ interface.

In more detail, this PR:

* Merges `librustrt` back into `std::rt`, undoing the facade. While doing so, it removes a substantial amount of redundant functionality (such as mutexes defined in the `rt` module). Code using `librustrt` can now call into `std::rt` to e.g. start executing Rust code with unwinding support.

* Allows all runtime data to be initialized lazily, including the "current thread", the "at_exit" infrastructure, and the "args" storage.

* Deprecates and largely removes `std::task` along with the widespread requirement that there be a "current task" for many APIs in `std`. The entire task infrastructure is replaced with `std::thread`, which provides a more standard API for manipulating and creating native OS threads. In particular, it's possible to join on a created thread, and to get a handle to the currently-running thread. In addition, threads are equipped with some basic blocking support in the form of `park`/`unpark` operations (following a tradition in some OSes as well as the JVM). See the `std::thread` documentation for more details.

* Channels are refactored to use a new internal blocking infrastructure that itself sits on top of `park`/`unpark`.

One important change here is that a Rust program ends when its main thread does, following most threading models. On the other hand, threads will often be created with an RAII-style join handle that will re-institute blocking semantics naturally (and with finer control).

This is very much a:

[breaking-change]

Closes #18000
r? @alexcrichton 
Diffstat (limited to 'src/libstd/sync')
-rw-r--r--src/libstd/sync/atomic.rs10
-rw-r--r--src/libstd/sync/barrier.rs5
-rw-r--r--src/libstd/sync/condvar.rs6
-rw-r--r--src/libstd/sync/future.rs6
-rw-r--r--src/libstd/sync/mutex.rs15
-rw-r--r--src/libstd/sync/once.rs4
-rw-r--r--src/libstd/sync/poison.rs18
-rw-r--r--src/libstd/sync/rwlock.rs34
-rw-r--r--src/libstd/sync/task_pool.rs7
9 files changed, 49 insertions, 56 deletions
diff --git a/src/libstd/sync/atomic.rs b/src/libstd/sync/atomic.rs
index fe5b962fa4b..26778ef70b3 100644
--- a/src/libstd/sync/atomic.rs
+++ b/src/libstd/sync/atomic.rs
@@ -42,14 +42,15 @@
 //! ```
 //! use std::sync::Arc;
 //! use std::sync::atomic::{AtomicUint, SeqCst};
+//! use std::thread::Thread;
 //!
 //! fn main() {
 //!     let spinlock = Arc::new(AtomicUint::new(1));
 //!
 //!     let spinlock_clone = spinlock.clone();
-//!     spawn(move|| {
+//!     Thread::spawn(move|| {
 //!         spinlock_clone.store(0, SeqCst);
-//!     });
+//!     }).detach();
 //!
 //!     // Wait for the other task to release the lock
 //!     while spinlock.load(SeqCst) != 0 {}
@@ -61,6 +62,7 @@
 //! ```
 //! use std::sync::Arc;
 //! use std::sync::atomic::{AtomicOption, SeqCst};
+//! use std::thread::Thread;
 //!
 //! fn main() {
 //!     struct BigObject;
@@ -68,14 +70,14 @@
 //!     let shared_big_object = Arc::new(AtomicOption::empty());
 //!
 //!     let shared_big_object_clone = shared_big_object.clone();
-//!     spawn(move|| {
+//!     Thread::spawn(move|| {
 //!         let unwrapped_big_object = shared_big_object_clone.take(SeqCst);
 //!         if unwrapped_big_object.is_some() {
 //!             println!("got a big object from another task");
 //!         } else {
 //!             println!("other task hasn't sent big object yet");
 //!         }
-//!     });
+//!     }).detach();
 //!
 //!     shared_big_object.swap(box BigObject, SeqCst);
 //! }
diff --git a/src/libstd/sync/barrier.rs b/src/libstd/sync/barrier.rs
index 1b8574604a0..6573d9273ce 100644
--- a/src/libstd/sync/barrier.rs
+++ b/src/libstd/sync/barrier.rs
@@ -15,17 +15,18 @@ use sync::{Mutex, Condvar};
 ///
 /// ```rust
 /// use std::sync::{Arc, Barrier};
+/// use std::thread::Thread;
 ///
 /// let barrier = Arc::new(Barrier::new(10));
 /// for _ in range(0u, 10) {
 ///     let c = barrier.clone();
 ///     // The same messages will be printed together.
 ///     // You will NOT see any interleaving.
-///     spawn(move|| {
+///     Thread::spawn(move|| {
 ///         println!("before wait");
 ///         c.wait();
 ///         println!("after wait");
-///     });
+///     }).detach();
 /// }
 /// ```
 pub struct Barrier {
diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs
index 3bdab261e19..be27c06b83c 100644
--- a/src/libstd/sync/condvar.rs
+++ b/src/libstd/sync/condvar.rs
@@ -36,17 +36,18 @@ use time::Duration;
 ///
 /// ```
 /// use std::sync::{Arc, Mutex, Condvar};
+/// use std::thread::Thread;
 ///
 /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
 /// let pair2 = pair.clone();
 ///
 /// // Inside of our lock, spawn a new thread, and then wait for it to start
-/// spawn(move|| {
+/// Thread::spawn(move|| {
 ///     let &(ref lock, ref cvar) = &*pair2;
 ///     let mut started = lock.lock();
 ///     *started = true;
 ///     cvar.notify_one();
-/// });
+/// }).detach();
 ///
 /// // wait for the thread to start up
 /// let &(ref lock, ref cvar) = &*pair;
@@ -362,4 +363,3 @@ mod tests {
 
     }
 }
-
diff --git a/src/libstd/sync/future.rs b/src/libstd/sync/future.rs
index e5a1e09967c..5e9d234c642 100644
--- a/src/libstd/sync/future.rs
+++ b/src/libstd/sync/future.rs
@@ -29,8 +29,8 @@ use core::mem::replace;
 
 use self::FutureState::*;
 use comm::{Receiver, channel};
-use task::spawn;
 use thunk::{Thunk};
+use thread::Thread;
 
 /// A type encapsulating the result of a computation which may not be complete
 pub struct Future<A> {
@@ -139,10 +139,10 @@ impl<A:Send> Future<A> {
 
         let (tx, rx) = channel();
 
-        spawn(move |:| {
+        Thread::spawn(move |:| {
             // Don't panic if the other end has hung up
             let _ = tx.send_opt(blk());
-        });
+        }).detach();
 
         Future::from_receiver(rx)
     }
diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs
index 33f8d254c71..4829be569cc 100644
--- a/src/libstd/sync/mutex.rs
+++ b/src/libstd/sync/mutex.rs
@@ -35,6 +35,7 @@ use sys_common::mutex as sys;
 ///
 /// ```rust
 /// use std::sync::{Arc, Mutex};
+/// use std::thread::Thread;
 /// const N: uint = 10;
 ///
 /// // Spawn a few threads to increment a shared variable (non-atomically), and
@@ -47,7 +48,7 @@ use sys_common::mutex as sys;
 /// let (tx, rx) = channel();
 /// for _ in range(0u, 10) {
 ///     let (data, tx) = (data.clone(), tx.clone());
-///     spawn(move|| {
+///     Thread::spawn(move|| {
 ///         // The shared static can only be accessed once the lock is held.
 ///         // Our non-atomic increment is safe because we're the only thread
 ///         // which can access the shared state when the lock is held.
@@ -57,7 +58,7 @@ use sys_common::mutex as sys;
 ///             tx.send(());
 ///         }
 ///         // the lock is unlocked here when `data` goes out of scope.
-///     });
+///     }).detach();
 /// }
 ///
 /// rx.recv();
@@ -274,7 +275,7 @@ impl Drop for StaticMutexGuard {
 mod test {
     use prelude::*;
 
-    use task;
+    use thread::Thread;
     use sync::{Arc, Mutex, StaticMutex, MUTEX_INIT, Condvar};
 
     #[test]
@@ -386,10 +387,10 @@ mod test {
     fn test_mutex_arc_poison() {
         let arc = Arc::new(Mutex::new(1i));
         let arc2 = arc.clone();
-        let _ = task::try(move|| {
+        let _ = Thread::spawn(move|| {
             let lock = arc2.lock();
             assert_eq!(*lock, 2);
-        });
+        }).join();
         let lock = arc.lock();
         assert_eq!(*lock, 1);
     }
@@ -414,7 +415,7 @@ mod test {
     fn test_mutex_arc_access_in_unwind() {
         let arc = Arc::new(Mutex::new(1i));
         let arc2 = arc.clone();
-        let _ = task::try(move|| -> () {
+        let _ = Thread::spawn(move|| -> () {
             struct Unwinder {
                 i: Arc<Mutex<int>>,
             }
@@ -425,7 +426,7 @@ mod test {
             }
             let _u = Unwinder { i: arc2 };
             panic!();
-        });
+        }).join();
         let lock = arc.lock();
         assert_eq!(*lock, 2);
     }
diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs
index 263937c5cbe..a43f822e351 100644
--- a/src/libstd/sync/once.rs
+++ b/src/libstd/sync/once.rs
@@ -121,7 +121,7 @@ impl Once {
 mod test {
     use prelude::*;
 
-    use task;
+    use thread::Thread;
     use super::{ONCE_INIT, Once};
 
     #[test]
@@ -143,7 +143,7 @@ mod test {
         for _ in range(0u, 10) {
             let tx = tx.clone();
             spawn(move|| {
-                for _ in range(0u, 4) { task::deschedule() }
+                for _ in range(0u, 4) { Thread::yield_now() }
                 unsafe {
                     O.doit(|| {
                         assert!(!run);
diff --git a/src/libstd/sync/poison.rs b/src/libstd/sync/poison.rs
index ee151556620..ad08e9873fa 100644
--- a/src/libstd/sync/poison.rs
+++ b/src/libstd/sync/poison.rs
@@ -8,21 +8,19 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use option::Option::None;
-use rustrt::task::Task;
-use rustrt::local::Local;
+use thread::Thread;
 
 pub struct Flag { pub failed: bool }
 
 impl Flag {
     pub fn borrow(&mut self) -> Guard {
-        Guard { flag: &mut self.failed, failing: failing() }
+        Guard { flag: &mut self.failed, panicking: Thread::panicking() }
     }
 }
 
 pub struct Guard<'a> {
     flag: &'a mut bool,
-    failing: bool,
+    panicking: bool,
 }
 
 impl<'a> Guard<'a> {
@@ -33,16 +31,8 @@ impl<'a> Guard<'a> {
     }
 
     pub fn done(&mut self) {
-        if !self.failing && failing() {
+        if !self.panicking && Thread::panicking() {
             *self.flag = true;
         }
     }
 }
-
-fn failing() -> bool {
-    if Local::exists(None::<Task>) {
-        Local::borrow(None::<Task>).unwinder.unwinding()
-    } else {
-        false
-    }
-}
diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs
index b6d6aa989c5..07b2f2cf541 100644
--- a/src/libstd/sync/rwlock.rs
+++ b/src/libstd/sync/rwlock.rs
@@ -356,7 +356,7 @@ mod tests {
     use prelude::*;
 
     use rand::{mod, Rng};
-    use task;
+    use thread::Thread;
     use sync::{Arc, RWLock, StaticRWLock, RWLOCK_INIT};
 
     #[test]
@@ -409,10 +409,10 @@ mod tests {
     fn test_rw_arc_poison_wr() {
         let arc = Arc::new(RWLock::new(1i));
         let arc2 = arc.clone();
-        let _ = task::try(move|| {
+        let _ = Thread::spawn(move|| {
             let lock = arc2.write();
             assert_eq!(*lock, 2);
-        });
+        }).join();
         let lock = arc.read();
         assert_eq!(*lock, 1);
     }
@@ -422,10 +422,10 @@ mod tests {
     fn test_rw_arc_poison_ww() {
         let arc = Arc::new(RWLock::new(1i));
         let arc2 = arc.clone();
-        let _ = task::try(move|| {
+        let _ = Thread::spawn(move|| {
             let lock = arc2.write();
             assert_eq!(*lock, 2);
-        });
+        }).join();
         let lock = arc.write();
         assert_eq!(*lock, 1);
     }
@@ -434,10 +434,10 @@ mod tests {
     fn test_rw_arc_no_poison_rr() {
         let arc = Arc::new(RWLock::new(1i));
         let arc2 = arc.clone();
-        let _ = task::try(move|| {
+        let _ = Thread::spawn(move|| {
             let lock = arc2.read();
             assert_eq!(*lock, 2);
-        });
+        }).join();
         let lock = arc.read();
         assert_eq!(*lock, 1);
     }
@@ -445,10 +445,10 @@ mod tests {
     fn test_rw_arc_no_poison_rw() {
         let arc = Arc::new(RWLock::new(1i));
         let arc2 = arc.clone();
-        let _ = task::try(move|| {
+        let _ = Thread::spawn(move|| {
             let lock = arc2.read();
             assert_eq!(*lock, 2);
-        });
+        }).join();
         let lock = arc.write();
         assert_eq!(*lock, 1);
     }
@@ -459,30 +459,30 @@ mod tests {
         let arc2 = arc.clone();
         let (tx, rx) = channel();
 
-        task::spawn(move|| {
+        Thread::spawn(move|| {
             let mut lock = arc2.write();
             for _ in range(0u, 10) {
                 let tmp = *lock;
                 *lock = -1;
-                task::deschedule();
+                Thread::yield_now();
                 *lock = tmp + 1;
             }
             tx.send(());
-        });
+        }).detach();
 
         // Readers try to catch the writer in the act
         let mut children = Vec::new();
         for _ in range(0u, 5) {
             let arc3 = arc.clone();
-            children.push(task::try_future(move|| {
+            children.push(Thread::spawn(move|| {
                 let lock = arc3.read();
                 assert!(*lock >= 0);
             }));
         }
 
         // Wait for children to pass their asserts
-        for r in children.iter_mut() {
-            assert!(r.get_ref().is_ok());
+        for r in children.into_iter() {
+            assert!(r.join().is_ok());
         }
 
         // Wait for writer to finish
@@ -495,7 +495,7 @@ mod tests {
     fn test_rw_arc_access_in_unwind() {
         let arc = Arc::new(RWLock::new(1i));
         let arc2 = arc.clone();
-        let _ = task::try(move|| -> () {
+        let _ = Thread::spawn(move|| -> () {
             struct Unwinder {
                 i: Arc<RWLock<int>>,
             }
@@ -507,7 +507,7 @@ mod tests {
             }
             let _u = Unwinder { i: arc2 };
             panic!();
-        });
+        }).join();
         let lock = arc.read();
         assert_eq!(*lock, 2);
     }
diff --git a/src/libstd/sync/task_pool.rs b/src/libstd/sync/task_pool.rs
index fa5b62a202b..793825f1b08 100644
--- a/src/libstd/sync/task_pool.rs
+++ b/src/libstd/sync/task_pool.rs
@@ -12,7 +12,7 @@
 
 use core::prelude::*;
 
-use task::{spawn};
+use thread::Thread;
 use comm::{channel, Sender, Receiver};
 use sync::{Arc, Mutex};
 use thunk::Thunk;
@@ -105,7 +105,7 @@ impl TaskPool {
 }
 
 fn spawn_in_pool(jobs: Arc<Mutex<Receiver<Thunk>>>) {
-    spawn(move |:| {
+    Thread::spawn(move |:| {
         // Will spawn a new task on panic unless it is cancelled.
         let sentinel = Sentinel::new(&jobs);
 
@@ -126,7 +126,7 @@ fn spawn_in_pool(jobs: Arc<Mutex<Receiver<Thunk>>>) {
         }
 
         sentinel.cancel();
-    })
+    }).detach();
 }
 
 #[cfg(test)]
@@ -206,4 +206,3 @@ mod test {
         waiter.wait();
     }
 }
-