about summary refs log tree commit diff
path: root/library/std/src/thread
diff options
context:
space:
mode:
Diffstat (limited to 'library/std/src/thread')
-rw-r--r--library/std/src/thread/current.rs17
-rw-r--r--library/std/src/thread/mod.rs15
-rw-r--r--library/std/src/thread/scoped.rs7
3 files changed, 33 insertions, 6 deletions
diff --git a/library/std/src/thread/current.rs b/library/std/src/thread/current.rs
index e6eb90c4c30..b9b959f9894 100644
--- a/library/std/src/thread/current.rs
+++ b/library/std/src/thread/current.rs
@@ -165,6 +165,23 @@ pub(crate) fn try_current() -> Option<Thread> {
     }
 }
 
+/// Gets a handle to the thread that invokes it. If the handle stored in thread-
+/// local storage was already destroyed, this creates a new unnamed temporary
+/// handle to allow thread parking in nearly all situations.
+pub(crate) fn current_or_unnamed() -> Thread {
+    let current = CURRENT.get();
+    if current > DESTROYED {
+        unsafe {
+            let current = ManuallyDrop::new(Thread::from_raw(current));
+            (*current).clone()
+        }
+    } else if current == DESTROYED {
+        Thread::new_unnamed(id::get_or_init())
+    } else {
+        init_current(current)
+    }
+}
+
 /// Gets a handle to the thread that invokes it.
 ///
 /// # Examples
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index 2c2cc58a9dd..2ff44fcd4c6 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -186,7 +186,7 @@ mod current;
 
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use current::current;
-pub(crate) use current::{current_id, drop_current, set_current, try_current};
+pub(crate) use current::{current_id, current_or_unnamed, drop_current, set_current, try_current};
 
 mod spawnhook;
 
@@ -1146,9 +1146,9 @@ pub fn park_timeout_ms(ms: u32) {
 #[stable(feature = "park_timeout", since = "1.4.0")]
 pub fn park_timeout(dur: Duration) {
     let guard = PanicGuard;
-    // SAFETY: park_timeout is called on the parker owned by this thread.
+    // SAFETY: park_timeout is called on a handle owned by this thread.
     unsafe {
-        current().0.parker().park_timeout(dur);
+        current().park_timeout(dur);
     }
     // No panic occurred, do not abort.
     forget(guard);
@@ -1446,6 +1446,15 @@ impl Thread {
         unsafe { self.0.parker().park() }
     }
 
+    /// Like the public [`park_timeout`], but callable on any handle. This is
+    /// used to allow parking in TLS destructors.
+    ///
+    /// # Safety
+    /// May only be called from the thread to which this handle belongs.
+    pub(crate) unsafe fn park_timeout(&self, dur: Duration) {
+        unsafe { self.0.parker().park_timeout(dur) }
+    }
+
     /// Atomically makes the handle's token available if it is not already.
     ///
     /// Every thread is equipped with some basic low-level blocking support, via
diff --git a/library/std/src/thread/scoped.rs b/library/std/src/thread/scoped.rs
index a14446b3515..0033fc3a732 100644
--- a/library/std/src/thread/scoped.rs
+++ b/library/std/src/thread/scoped.rs
@@ -1,4 +1,4 @@
-use super::{Builder, JoinInner, Result, Thread, current, park};
+use super::{Builder, JoinInner, Result, Thread, current_or_unnamed};
 use crate::marker::PhantomData;
 use crate::panic::{AssertUnwindSafe, catch_unwind, resume_unwind};
 use crate::sync::Arc;
@@ -140,7 +140,7 @@ where
     let scope = Scope {
         data: Arc::new(ScopeData {
             num_running_threads: AtomicUsize::new(0),
-            main_thread: current(),
+            main_thread: current_or_unnamed(),
             a_thread_panicked: AtomicBool::new(false),
         }),
         env: PhantomData,
@@ -152,7 +152,8 @@ where
 
     // Wait until all the threads are finished.
     while scope.data.num_running_threads.load(Ordering::Acquire) != 0 {
-        park();
+        // SAFETY: this is the main thread, the handle belongs to us.
+        unsafe { scope.data.main_thread.park() };
     }
 
     // Throw any panic from `f`, or the return value of `f` if no thread panicked.