@@ -35,10 +35,13 @@ pub struct Scope<'scope, 'env: 'scope> {
35
35
#[ stable( feature = "scoped_threads" , since = "1.63.0" ) ]
36
36
pub struct ScopedJoinHandle < ' scope , T > ( JoinInner < ' scope , T > ) ;
37
37
38
+ // Note: all of `ScopeData` fields must be interiorly mutable since
39
+ // it may be deallocated in the middle of a `&self` method:
40
+ // see `decrement_num_running_threads` below for more info.
38
41
pub ( super ) struct ScopeData {
39
42
num_running_threads : AtomicUsize ,
40
43
a_thread_panicked : AtomicBool ,
41
- main_thread : Thread ,
44
+ main_thread : UnsafeCell < Thread > ,
42
45
}
43
46
44
47
impl ScopeData {
@@ -51,12 +54,24 @@ impl ScopeData {
51
54
panic ! ( "too many running threads in thread scope" ) ;
52
55
}
53
56
}
57
+ fn main_thread ( & self ) -> & Thread {
58
+ unsafe { & * self . main_thread . get ( ) }
59
+ }
54
60
pub ( super ) fn decrement_num_running_threads ( & self , panic : bool ) {
55
61
if panic {
56
62
self . a_thread_panicked . store ( true , Ordering :: Relaxed ) ;
57
63
}
64
+ let main_thread = self . main_thread ( ) . clone ( ) ;
58
65
if self . num_running_threads . fetch_sub ( 1 , Ordering :: Release ) == 1 {
59
- self . main_thread . unpark ( ) ;
66
+ // By now, `num_running_threads` is `0`, so when `scope()` in the main thread
67
+ // is unparked, it will complete its business and deallocate `*self`!
68
+ // Two things to look after:
69
+ // - it can spuriously unpark / wake up, **so `self` can no longer be used**, even
70
+ // before we, ourselves, unpark. Hence why we've cloned the `main_thread`'s handle.
71
+ // - no matter how it unparks, `*self` may be deallocated before this function
72
+ // returns, so all of `*self` data, **including `main_thread`**, must be interiorly
73
+ // mutable. See https://github.com/rust-lang/rust/issues/55005 for more info.
74
+ main_thread. unpark ( ) ;
60
75
}
61
76
}
62
77
}
@@ -133,7 +148,7 @@ where
133
148
let scope = Scope {
134
149
data : ScopeData {
135
150
num_running_threads : AtomicUsize :: new ( 0 ) ,
136
- main_thread : current ( ) ,
151
+ main_thread : current ( ) . into ( ) ,
137
152
a_thread_panicked : AtomicBool :: new ( false ) ,
138
153
} ,
139
154
env : PhantomData ,
@@ -328,7 +343,7 @@ impl fmt::Debug for Scope<'_, '_> {
328
343
f. debug_struct ( "Scope" )
329
344
. field ( "num_running_threads" , & self . data . num_running_threads . load ( Ordering :: Relaxed ) )
330
345
. field ( "a_thread_panicked" , & self . data . a_thread_panicked . load ( Ordering :: Relaxed ) )
331
- . field ( "main_thread" , & self . data . main_thread )
346
+ . field ( "main_thread" , self . data . main_thread ( ) )
332
347
. finish_non_exhaustive ( )
333
348
}
334
349
}
0 commit comments