diff options
| author | Ralf Jung <post@ralfj.de> | 2022-06-25 16:30:57 -0400 |
|---|---|---|
| committer | Ralf Jung <post@ralfj.de> | 2022-06-27 16:50:42 -0400 |
| commit | af0c1fe83dcbb3b5b651962095ed9784a6746308 (patch) | |
| tree | e6d54718f8fad43f9e20e81de046f0f36ae599c8 /library/std/src/thread | |
| parent | 1aabd8a4a6e1871f14e804302bd60dfcbffd5761 (diff) | |
| download | rust-af0c1fe83dcbb3b5b651962095ed9784a6746308.tar.gz rust-af0c1fe83dcbb3b5b651962095ed9784a6746308.zip | |
fix data race in thread::scope
Diffstat (limited to 'library/std/src/thread')
| -rw-r--r-- | library/std/src/thread/mod.rs | 17 | ||||
| -rw-r--r-- | library/std/src/thread/scoped.rs | 10 |
2 files changed, 17 insertions, 10 deletions
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 0a6a7cfe976..c70ac8c9806 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -159,6 +159,7 @@ use crate::cell::UnsafeCell; use crate::ffi::{CStr, CString}; use crate::fmt; use crate::io; +use crate::marker::PhantomData; use crate::mem; use crate::num::NonZeroU64; use crate::num::NonZeroUsize; @@ -462,7 +463,7 @@ impl Builder { unsafe fn spawn_unchecked_<'a, 'scope, F, T>( self, f: F, - scope_data: Option<&'scope scoped::ScopeData>, + scope_data: Option<Arc<scoped::ScopeData>>, ) -> io::Result<JoinInner<'scope, T>> where F: FnOnce() -> T, @@ -479,8 +480,11 @@ impl Builder { })); let their_thread = my_thread.clone(); - let my_packet: Arc<Packet<'scope, T>> = - Arc::new(Packet { scope: scope_data, result: UnsafeCell::new(None) }); + let my_packet: Arc<Packet<'scope, T>> = Arc::new(Packet { + scope: scope_data, + result: UnsafeCell::new(None), + _marker: PhantomData, + }); let their_packet = my_packet.clone(); let output_capture = crate::io::set_output_capture(None); @@ -507,7 +511,7 @@ impl Builder { unsafe { *their_packet.result.get() = Some(try_result) }; }; - if let Some(scope_data) = scope_data { + if let Some(scope_data) = &my_packet.scope { scope_data.increment_num_running_threads(); } @@ -1298,8 +1302,9 @@ pub type Result<T> = crate::result::Result<T, Box<dyn Any + Send + 'static>>; // An Arc to the packet is stored into a `JoinInner` which in turns is placed // in `JoinHandle`. struct Packet<'scope, T> { - scope: Option<&'scope scoped::ScopeData>, + scope: Option<Arc<scoped::ScopeData>>, result: UnsafeCell<Option<Result<T>>>, + _marker: PhantomData<Option<&'scope scoped::ScopeData>>, } // Due to the usage of `UnsafeCell` we need to manually implement Sync. @@ -1330,7 +1335,7 @@ impl<'scope, T> Drop for Packet<'scope, T> { rtabort!("thread result panicked on drop"); } // Book-keeping so the scope knows when it's done. - if let Some(scope) = self.scope { + if let Some(scope) = &self.scope { // Now that there will be no more user code running on this thread // that can use 'scope, mark the thread as 'finished'. // It's important we only do this after the `result` has been dropped, diff --git a/library/std/src/thread/scoped.rs b/library/std/src/thread/scoped.rs index a387a09dc8b..e6dbf35bd02 100644 --- a/library/std/src/thread/scoped.rs +++ b/library/std/src/thread/scoped.rs @@ -11,7 +11,7 @@ use crate::sync::Arc; /// See [`scope`] for details. #[stable(feature = "scoped_threads", since = "1.63.0")] pub struct Scope<'scope, 'env: 'scope> { - data: ScopeData, + data: Arc<ScopeData>, /// Invariance over 'scope, to make sure 'scope cannot shrink, /// which is necessary for soundness. /// @@ -130,12 +130,14 @@ pub fn scope<'env, F, T>(f: F) -> T where F: for<'scope> FnOnce(&'scope Scope<'scope, 'env>) -> T, { + // We put the `ScopeData` into an `Arc` so that other threads can finish their + // `decrement_num_running_threads` even after this function returns. let scope = Scope { - data: ScopeData { + data: Arc::new(ScopeData { num_running_threads: AtomicUsize::new(0), main_thread: current(), a_thread_panicked: AtomicBool::new(false), - }, + }), env: PhantomData, scope: PhantomData, }; @@ -250,7 +252,7 @@ impl Builder { F: FnOnce() -> T + Send + 'scope, T: Send + 'scope, { - Ok(ScopedJoinHandle(unsafe { self.spawn_unchecked_(f, Some(&scope.data)) }?)) + Ok(ScopedJoinHandle(unsafe { self.spawn_unchecked_(f, Some(scope.data.clone())) }?)) } } |
