@@ -180,6 +180,12 @@ use crate::time::Duration;
180
180
#[ macro_use]
181
181
mod local;
182
182
183
+ #[ unstable( feature = "scoped_threads" , issue = "93203" ) ]
184
+ mod scoped;
185
+
186
+ #[ unstable( feature = "scoped_threads" , issue = "93203" ) ]
187
+ pub use scoped:: { scope, Scope , ScopedJoinHandle } ;
188
+
183
189
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
184
190
pub use self :: local:: { AccessError , LocalKey } ;
185
191
@@ -446,6 +452,20 @@ impl Builder {
446
452
F : FnOnce ( ) -> T ,
447
453
F : Send + ' a ,
448
454
T : Send + ' a ,
455
+ {
456
+ Ok ( JoinHandle ( unsafe { self . spawn_unchecked_ ( f, None ) } ?) )
457
+ }
458
+
459
+ unsafe fn spawn_unchecked_ < ' a , ' scope , F , T > (
460
+ self ,
461
+ f : F ,
462
+ scope_data : Option < & ' scope scoped:: ScopeData > ,
463
+ ) -> io:: Result < JoinInner < ' scope , T > >
464
+ where
465
+ F : FnOnce ( ) -> T ,
466
+ F : Send + ' a ,
467
+ T : Send + ' a ,
468
+ ' scope : ' a ,
449
469
{
450
470
let Builder { name, stack_size } = self ;
451
471
@@ -456,7 +476,8 @@ impl Builder {
456
476
} ) ) ;
457
477
let their_thread = my_thread. clone ( ) ;
458
478
459
- let my_packet: Arc < UnsafeCell < Option < Result < T > > > > = Arc :: new ( UnsafeCell :: new ( None ) ) ;
479
+ let my_packet: Arc < Packet < ' scope , T > > =
480
+ Arc :: new ( Packet { scope : scope_data, result : UnsafeCell :: new ( None ) } ) ;
460
481
let their_packet = my_packet. clone ( ) ;
461
482
462
483
let output_capture = crate :: io:: set_output_capture ( None ) ;
@@ -480,10 +501,14 @@ impl Builder {
480
501
// closure (it is an Arc<...>) and `my_packet` will be stored in the
481
502
// same `JoinInner` as this closure meaning the mutation will be
482
503
// safe (not modify it and affect a value far away).
483
- unsafe { * their_packet. get ( ) = Some ( try_result) } ;
504
+ unsafe { * their_packet. result . get ( ) = Some ( try_result) } ;
484
505
} ;
485
506
486
- Ok ( JoinHandle ( JoinInner {
507
+ if let Some ( scope_data) = scope_data {
508
+ scope_data. increment_num_running_threads ( ) ;
509
+ }
510
+
511
+ Ok ( JoinInner {
487
512
// SAFETY:
488
513
//
489
514
// `imp::Thread::new` takes a closure with a `'static` lifetime, since it's passed
@@ -506,8 +531,8 @@ impl Builder {
506
531
) ?
507
532
} ,
508
533
thread : my_thread,
509
- packet : Packet ( my_packet) ,
510
- } ) )
534
+ packet : my_packet,
535
+ } )
511
536
}
512
537
}
513
538
@@ -1242,34 +1267,48 @@ impl fmt::Debug for Thread {
1242
1267
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
1243
1268
pub type Result < T > = crate :: result:: Result < T , Box < dyn Any + Send + ' static > > ;
1244
1269
1245
- // This packet is used to communicate the return value between the spawned thread
1246
- // and the rest of the program. Memory is shared through the `Arc` within and there's
1247
- // no need for a mutex here because synchronization happens with `join()` (the
1248
- // caller will never read this packet until the thread has exited).
1270
+ // This packet is used to communicate the return value between the spawned
1271
+ // thread and the rest of the program. It is shared through an `Arc` and
1272
+ // there's no need for a mutex here because synchronization happens with `join()`
1273
+ // (the caller will never read this packet until the thread has exited).
1249
1274
//
1250
- // This packet itself is then stored into a `JoinInner` which in turns is placed
1251
- // in `JoinHandle` and `JoinGuard`. Due to the usage of `UnsafeCell` we need to
1252
- // manually worry about impls like Send and Sync. The type `T` should
1253
- // already always be Send (otherwise the thread could not have been created) and
1254
- // this type is inherently Sync because no methods take &self. Regardless,
1255
- // however, we add inheriting impls for Send/Sync to this type to ensure it's
1256
- // Send/Sync and that future modifications will still appropriately classify it.
1257
- struct Packet < T > ( Arc < UnsafeCell < Option < Result < T > > > > ) ;
1258
-
1259
- unsafe impl < T : Send > Send for Packet < T > { }
1260
- unsafe impl < T : Sync > Sync for Packet < T > { }
1275
+ // An Arc to the packet is stored into a `JoinInner` which in turns is placed
1276
+ // in `JoinHandle`.
1277
+ struct Packet < ' scope , T > {
1278
+ scope : Option < & ' scope scoped:: ScopeData > ,
1279
+ result : UnsafeCell < Option < Result < T > > > ,
1280
+ }
1281
+
1282
+ // Due to the usage of `UnsafeCell` we need to manually implement Sync.
1283
+ // The type `T` should already always be Send (otherwise the thread could not
1284
+ // have been created) and the Packet is Sync because all access to the
1285
+ // `UnsafeCell` synchronized (by the `join()` boundary), and `ScopeData` is Sync.
1286
+ unsafe impl < ' scope , T : Sync > Sync for Packet < ' scope , T > { }
1287
+
1288
+ impl < ' scope , T > Drop for Packet < ' scope , T > {
1289
+ fn drop ( & mut self ) {
1290
+ // Book-keeping so the scope knows when it's done.
1291
+ if let Some ( scope) = self . scope {
1292
+ // If this packet was for a thread that ran in a scope, the thread
1293
+ // panicked, and nobody consumed the panic payload, we make sure
1294
+ // the scope function will panic.
1295
+ let unhandled_panic = matches ! ( self . result. get_mut( ) , Some ( Err ( _) ) ) ;
1296
+ scope. decrement_num_running_threads ( unhandled_panic) ;
1297
+ }
1298
+ }
1299
+ }
1261
1300
1262
1301
/// Inner representation for JoinHandle
1263
- struct JoinInner < T > {
1302
+ struct JoinInner < ' scope , T > {
1264
1303
native : imp:: Thread ,
1265
1304
thread : Thread ,
1266
- packet : Packet < T > ,
1305
+ packet : Arc < Packet < ' scope , T > > ,
1267
1306
}
1268
1307
1269
- impl < T > JoinInner < T > {
1308
+ impl < ' scope , T > JoinInner < ' scope , T > {
1270
1309
fn join ( mut self ) -> Result < T > {
1271
1310
self . native . join ( ) ;
1272
- Arc :: get_mut ( & mut self . packet . 0 ) . unwrap ( ) . get_mut ( ) . take ( ) . unwrap ( )
1311
+ Arc :: get_mut ( & mut self . packet ) . unwrap ( ) . result . get_mut ( ) . take ( ) . unwrap ( )
1273
1312
}
1274
1313
}
1275
1314
@@ -1336,7 +1375,7 @@ impl<T> JoinInner<T> {
1336
1375
/// [`thread::Builder::spawn`]: Builder::spawn
1337
1376
/// [`thread::spawn`]: spawn
1338
1377
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
1339
- pub struct JoinHandle < T > ( JoinInner < T > ) ;
1378
+ pub struct JoinHandle < T > ( JoinInner < ' static , T > ) ;
1340
1379
1341
1380
#[ stable( feature = "joinhandle_impl_send_sync" , since = "1.29.0" ) ]
1342
1381
unsafe impl < T > Send for JoinHandle < T > { }
@@ -1404,13 +1443,13 @@ impl<T> JoinHandle<T> {
1404
1443
self . 0 . join ( )
1405
1444
}
1406
1445
1407
- /// Checks if the the associated thread is still running its main function.
1446
+ /// Checks if the associated thread is still running its main function.
1408
1447
///
1409
1448
/// This might return `false` for a brief moment after the thread's main
1410
1449
/// function has returned, but before the thread itself has stopped running.
1411
1450
#[ unstable( feature = "thread_is_running" , issue = "90470" ) ]
1412
1451
pub fn is_running ( & self ) -> bool {
1413
- Arc :: strong_count ( & self . 0 . packet . 0 ) > 1
1452
+ Arc :: strong_count ( & self . 0 . packet ) > 1
1414
1453
}
1415
1454
}
1416
1455
0 commit comments