Rollup merge of #149482 - RalfJung:scope-tls-dtors, r=joboet

thread::scope: document how join interacts with TLS destructors

Fixes https://github.com/rust-lang/rust/issues/116237 by documenting the current behavior regarding thread-local destructors as intended. (I'm not stoked about this, but documenting it is better than leaving it unclear.)

This also adds documentation for explicit `join` calls (both for scoped and regular threads), saying that those *will* wait for TLS destructors. That reflects my understanding of the current implementation, which calls `join` on the native thread handle. Are we okay with guaranteeing that? I think we should, so people have at least some chance of implementing "wait for all destructors" manually. This fixes https://github.com/rust-lang/rust/issues/127571.

Cc @rust-lang/libs-api
This commit is contained in:
Jonathan Brouwer 2026-01-29 17:47:31 +01:00 committed by GitHub
commit faa0d67374
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 7 additions and 0 deletions

View file

@ -101,6 +101,8 @@ impl<T> JoinHandle<T> {
/// Waits for the associated thread to finish.
///
/// This function will return immediately if the associated thread has already finished.
/// Otherwise, it fully waits for the thread to finish, including all destructors
/// for thread-local variables that might be running after the main function of the thread.
///
/// In terms of [atomic memory orderings], the completion of the associated
/// thread synchronizes with this function returning. In other words, all

View file

@ -80,6 +80,9 @@ impl ScopeData {
///
/// All threads spawned within the scope that haven't been manually joined
/// will be automatically joined before this function returns.
/// However, note that joining will only wait for the main function of these threads to finish; even
/// when this function returns, destructors of thread-local variables in these threads might still
/// be running.
///
/// # Panics
///
@ -290,6 +293,8 @@ impl<'scope, T> ScopedJoinHandle<'scope, T> {
/// Waits for the associated thread to finish.
///
/// This function will return immediately if the associated thread has already finished.
/// Otherwise, it fully waits for the thread to finish, including all destructors
/// for thread-local variables that might be running after the main function of the thread.
///
/// In terms of [atomic memory orderings], the completion of the associated
/// thread synchronizes with this function returning.