1
1
use super :: { current, park, Builder , JoinInner , Result , Thread } ;
2
- use crate :: any:: Any ;
3
2
use crate :: fmt;
4
3
use crate :: io;
5
4
use crate :: marker:: PhantomData ;
6
5
use crate :: panic:: { catch_unwind, resume_unwind, AssertUnwindSafe } ;
7
- use crate :: sync:: atomic:: { AtomicUsize , Ordering } ;
8
- use crate :: sync:: { Arc , Mutex } ;
6
+ use crate :: sync:: atomic:: { AtomicBool , AtomicUsize , Ordering } ;
7
+ use crate :: sync:: Arc ;
9
8
10
9
/// A scope to spawn scoped threads in.
11
10
///
@@ -22,8 +21,8 @@ pub struct ScopedJoinHandle<'scope, T>(JoinInner<'scope, T>);
22
21
23
22
pub ( super ) struct ScopeData {
24
23
n_running_threads : AtomicUsize ,
24
+ a_thread_panicked : AtomicBool ,
25
25
main_thread : Thread ,
26
- pub ( super ) panic_payload : Mutex < Option < Box < dyn Any + Send > > > ,
27
26
}
28
27
29
28
impl ScopeData {
@@ -32,11 +31,14 @@ impl ScopeData {
32
31
// chance it overflows to 0, which would result in unsoundness.
33
32
if self . n_running_threads . fetch_add ( 1 , Ordering :: Relaxed ) == usize:: MAX / 2 {
34
33
// This can only reasonably happen by mem::forget()'ing many many ScopedJoinHandles.
35
- self . decrement_n_running_threads ( ) ;
34
+ self . decrement_n_running_threads ( false ) ;
36
35
panic ! ( "too many running threads in thread scope" ) ;
37
36
}
38
37
}
39
- pub ( super ) fn decrement_n_running_threads ( & self ) {
38
+ pub ( super ) fn decrement_n_running_threads ( & self , panic : bool ) {
39
+ if panic {
40
+ self . a_thread_panicked . store ( true , Ordering :: Relaxed ) ;
41
+ }
40
42
if self . n_running_threads . fetch_sub ( 1 , Ordering :: Release ) == 1 {
41
43
self . main_thread . unpark ( ) ;
42
44
}
@@ -89,15 +91,16 @@ impl ScopeData {
89
91
/// a.push(4);
90
92
/// assert_eq!(x, a.len());
91
93
/// ```
94
+ #[ track_caller]
92
95
pub fn scope < ' env , F , T > ( f : F ) -> T
93
96
where
94
97
F : FnOnce ( & Scope < ' env > ) -> T ,
95
98
{
96
- let mut scope = Scope {
99
+ let scope = Scope {
97
100
data : ScopeData {
98
101
n_running_threads : AtomicUsize :: new ( 0 ) ,
99
102
main_thread : current ( ) ,
100
- panic_payload : Mutex :: new ( None ) ,
103
+ a_thread_panicked : AtomicBool :: new ( false ) ,
101
104
} ,
102
105
env : PhantomData ,
103
106
} ;
@@ -110,21 +113,11 @@ where
110
113
park ( ) ;
111
114
}
112
115
113
- // Throw any panic from `f` or from any panicked thread , or the return value of `f` otherwise .
116
+ // Throw any panic from `f`, or the return value of `f` if no thread panicked .
114
117
match result {
115
- Err ( e) => {
116
- // `f` itself panicked.
117
- resume_unwind ( e) ;
118
- }
119
- Ok ( result) => {
120
- if let Some ( panic_payload) = scope. data . panic_payload . get_mut ( ) . unwrap ( ) . take ( ) {
121
- // A thread panicked.
122
- resume_unwind ( panic_payload) ;
123
- } else {
124
- // Nothing panicked.
125
- result
126
- }
127
- }
118
+ Err ( e) => resume_unwind ( e) ,
119
+ Ok ( _) if scope. data . a_thread_panicked . load ( Ordering :: Relaxed ) => panic ! ( "a thread panicked" ) ,
120
+ Ok ( result) => result,
128
121
}
129
122
}
130
123
@@ -293,7 +286,8 @@ impl<'env> fmt::Debug for Scope<'env> {
293
286
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
294
287
f. debug_struct ( "Scope" )
295
288
. field ( "n_running_threads" , & self . data . n_running_threads . load ( Ordering :: Relaxed ) )
296
- . field ( "panic_payload" , & self . data . panic_payload )
289
+ . field ( "a_thread_panicked" , & self . data . a_thread_panicked )
290
+ . field ( "main_thread" , & self . data . main_thread )
297
291
. finish_non_exhaustive ( )
298
292
}
299
293
}
0 commit comments