aboutsummaryrefslogtreecommitdiff
path: root/ctr-std/src/thread
diff options
context:
space:
mode:
Diffstat (limited to 'ctr-std/src/thread')
-rw-r--r--ctr-std/src/thread/local.rs2
-rw-r--r--ctr-std/src/thread/mod.rs37
2 files changed, 26 insertions, 13 deletions
diff --git a/ctr-std/src/thread/local.rs b/ctr-std/src/thread/local.rs
index 40d3280..a170abb 100644
--- a/ctr-std/src/thread/local.rs
+++ b/ctr-std/src/thread/local.rs
@@ -276,7 +276,7 @@ impl<T: 'static> LocalKey<T> {
///
/// This will lazily initialize the value if this thread has not referenced
/// this key yet. If the key has been destroyed (which may happen if this is called
- /// in a destructor), this function will return a `ThreadLocalError`.
+ /// in a destructor), this function will return an [`AccessError`](struct.AccessError.html).
///
/// # Panics
///
diff --git a/ctr-std/src/thread/mod.rs b/ctr-std/src/thread/mod.rs
index 1b976b7..61c6084 100644
--- a/ctr-std/src/thread/mod.rs
+++ b/ctr-std/src/thread/mod.rs
@@ -731,7 +731,8 @@ const NOTIFIED: usize = 2;
/// specifying a maximum time to block the thread for.
///
/// * The [`unpark`] method on a [`Thread`] atomically makes the token available
-/// if it wasn't already.
+/// if it wasn't already. Because the token is initially absent, [`unpark`]
+/// followed by [`park`] will result in the second call returning immediately.
///
/// In other words, each [`Thread`] acts a bit like a spinlock that can be
/// locked and unlocked using `park` and `unpark`.
@@ -766,6 +767,8 @@ const NOTIFIED: usize = 2;
/// // Let some time pass for the thread to be spawned.
/// thread::sleep(Duration::from_millis(10));
///
+/// // There is no race condition here, if `unpark`
+/// // happens first, `park` will return immediately.
/// println!("Unpark the thread");
/// parked_thread.thread().unpark();
///
@@ -796,7 +799,10 @@ pub fn park() {
let mut m = thread.inner.lock.lock().unwrap();
match thread.inner.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) {
Ok(_) => {}
- Err(NOTIFIED) => return, // notified after we locked
+ Err(NOTIFIED) => {
+ thread.inner.state.store(EMPTY, SeqCst);
+ return;
+ } // should consume this notification, so prohibit spurious wakeups in next park.
Err(_) => panic!("inconsistent park state"),
}
loop {
@@ -882,7 +888,10 @@ pub fn park_timeout(dur: Duration) {
let m = thread.inner.lock.lock().unwrap();
match thread.inner.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) {
Ok(_) => {}
- Err(NOTIFIED) => return, // notified after we locked
+ Err(NOTIFIED) => {
+ thread.inner.state.store(EMPTY, SeqCst);
+ return;
+ } // should consume this notification, so prohibit spurious wakeups in next park.
Err(_) => panic!("inconsistent park_timeout state"),
}
@@ -931,24 +940,23 @@ pub struct ThreadId(u64);
impl ThreadId {
// Generate a new unique thread ID.
fn new() -> ThreadId {
+ // We never call `GUARD.init()`, so it is UB to attempt to
+ // acquire this mutex reentrantly!
static GUARD: mutex::Mutex = mutex::Mutex::new();
static mut COUNTER: u64 = 0;
unsafe {
- GUARD.lock();
+ let _guard = GUARD.lock();
// If we somehow use up all our bits, panic so that we're not
// covering up subtle bugs of IDs being reused.
if COUNTER == ::u64::MAX {
- GUARD.unlock();
panic!("failed to generate unique thread ID: bitspace exhausted");
}
let id = COUNTER;
COUNTER += 1;
- GUARD.unlock();
-
ThreadId(id)
}
}
@@ -1172,7 +1180,7 @@ impl fmt::Debug for Thread {
///
/// [`Result`]: ../../std/result/enum.Result.html
#[stable(feature = "rust1", since = "1.0.0")]
-pub type Result<T> = ::result::Result<T, Box<Any + Send + 'static>>;
+pub type Result<T> = ::result::Result<T, Box<dyn Any + Send + 'static>>;
// This packet is used to communicate the return value between the child thread
// and the parent thread. Memory is shared through the `Arc` within and there's
@@ -1273,6 +1281,11 @@ impl<T> JoinInner<T> {
#[stable(feature = "rust1", since = "1.0.0")]
pub struct JoinHandle<T>(JoinInner<T>);
+#[stable(feature = "joinhandle_impl_send_sync", since = "1.29.0")]
+unsafe impl<T> Send for JoinHandle<T> {}
+#[stable(feature = "joinhandle_impl_send_sync", since = "1.29.0")]
+unsafe impl<T> Sync for JoinHandle<T> {}
+
impl<T> JoinHandle<T> {
/// Extracts a handle to the underlying thread.
///
@@ -1435,7 +1448,7 @@ mod tests {
rx.recv().unwrap();
}
- fn avoid_copying_the_body<F>(spawnfn: F) where F: FnOnce(Box<Fn() + Send>) {
+ fn avoid_copying_the_body<F>(spawnfn: F) where F: FnOnce(Box<dyn Fn() + Send>) {
let (tx, rx) = channel();
let x: Box<_> = box 1;
@@ -1482,7 +1495,7 @@ mod tests {
// (well, it would if the constant were 8000+ - I lowered it to be more
// valgrind-friendly. try this at home, instead..!)
const GENERATIONS: u32 = 16;
- fn child_no(x: u32) -> Box<Fn() + Send> {
+ fn child_no(x: u32) -> Box<dyn Fn() + Send> {
return Box::new(move|| {
if x < GENERATIONS {
thread::spawn(move|| child_no(x+1)());
@@ -1528,10 +1541,10 @@ mod tests {
#[test]
fn test_try_panic_message_any() {
match thread::spawn(move|| {
- panic!(box 413u16 as Box<Any + Send>);
+ panic!(box 413u16 as Box<dyn Any + Send>);
}).join() {
Err(e) => {
- type T = Box<Any + Send>;
+ type T = Box<dyn Any + Send>;
assert!(e.is::<T>());
let any = e.downcast::<T>().unwrap();
assert!(any.is::<u16>());