@@ -37,6 +37,7 @@ use rustc_target::spec::{MergeFunctions, SanitizerSet};
37
37
use std:: any:: Any ;
38
38
use std:: fs;
39
39
use std:: io;
40
+ use std:: marker:: PhantomData ;
40
41
use std:: mem;
41
42
use std:: path:: { Path , PathBuf } ;
42
43
use std:: str;
@@ -475,10 +476,13 @@ pub fn start_async_codegen<B: ExtraBackendMethods>(
475
476
metadata_module,
476
477
crate_info,
477
478
478
- coordinator_send,
479
479
codegen_worker_receive,
480
480
shared_emitter_main,
481
- future : coordinator_thread,
481
+ coordinator : Coordinator {
482
+ sender : coordinator_send,
483
+ future : Some ( coordinator_thread) ,
484
+ phantom : PhantomData ,
485
+ } ,
482
486
output_filenames : tcx. output_filenames ( ( ) ) . clone ( ) ,
483
487
}
484
488
}
@@ -1273,6 +1277,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
1273
1277
// work to be done.
1274
1278
while !codegen_done
1275
1279
|| running > 0
1280
+ || main_thread_worker_state == MainThreadWorkerState :: LLVMing
1276
1281
|| ( !codegen_aborted
1277
1282
&& !( work_items. is_empty ( )
1278
1283
&& needs_fat_lto. is_empty ( )
@@ -1470,14 +1475,12 @@ fn start_executing_work<B: ExtraBackendMethods>(
1470
1475
if !cgcx. opts . unstable_opts . no_parallel_llvm {
1471
1476
helper. request_token ( ) ;
1472
1477
}
1473
- assert ! ( !codegen_aborted) ;
1474
1478
assert_eq ! ( main_thread_worker_state, MainThreadWorkerState :: Codegenning ) ;
1475
1479
main_thread_worker_state = MainThreadWorkerState :: Idle ;
1476
1480
}
1477
1481
1478
1482
Message :: CodegenComplete => {
1479
1483
codegen_done = true ;
1480
- assert ! ( !codegen_aborted) ;
1481
1484
assert_eq ! ( main_thread_worker_state, MainThreadWorkerState :: Codegenning ) ;
1482
1485
main_thread_worker_state = MainThreadWorkerState :: Idle ;
1483
1486
}
@@ -1489,10 +1492,8 @@ fn start_executing_work<B: ExtraBackendMethods>(
1489
1492
// then conditions above will ensure no more work is spawned but
1490
1493
// we'll keep executing this loop until `running` hits 0.
1491
1494
Message :: CodegenAborted => {
1492
- assert ! ( !codegen_aborted) ;
1493
1495
codegen_done = true ;
1494
1496
codegen_aborted = true ;
1495
- assert_eq ! ( main_thread_worker_state, MainThreadWorkerState :: Codegenning ) ;
1496
1497
}
1497
1498
Message :: Done { result : Ok ( compiled_module) , worker_id } => {
1498
1499
free_worker ( worker_id) ;
@@ -1532,13 +1533,20 @@ fn start_executing_work<B: ExtraBackendMethods>(
1532
1533
Message :: Done { result : Err ( None ) , worker_id : _ } => {
1533
1534
bug ! ( "worker thread panicked" ) ;
1534
1535
}
1535
- Message :: Done { result : Err ( Some ( WorkerFatalError ) ) , worker_id : _ } => {
1536
- return Err ( ( ) ) ;
1536
+ Message :: Done { result : Err ( Some ( WorkerFatalError ) ) , worker_id } => {
1537
+ // Similar to CodegenAborted, wait for remaining work to finish.
1538
+ free_worker ( worker_id) ;
1539
+ codegen_done = true ;
1540
+ codegen_aborted = true ;
1537
1541
}
1538
1542
Message :: CodegenItem => bug ! ( "the coordinator should not receive codegen requests" ) ,
1539
1543
}
1540
1544
}
1541
1545
1546
+ if codegen_aborted {
1547
+ return Err ( ( ) ) ;
1548
+ }
1549
+
1542
1550
let needs_link = mem:: take ( & mut needs_link) ;
1543
1551
if !needs_link. is_empty ( ) {
1544
1552
assert ! ( compiled_modules. is_empty( ) ) ;
@@ -1828,25 +1836,47 @@ impl SharedEmitterMain {
1828
1836
}
1829
1837
}
1830
1838
1839
+ pub struct Coordinator < B : ExtraBackendMethods > {
1840
+ pub sender : Sender < Box < dyn Any + Send > > ,
1841
+ future : Option < thread:: JoinHandle < Result < CompiledModules , ( ) > > > ,
1842
+ // Only used for the Message type.
1843
+ phantom : PhantomData < B > ,
1844
+ }
1845
+
1846
+ impl < B : ExtraBackendMethods > Coordinator < B > {
1847
+ fn join ( mut self ) -> std:: thread:: Result < Result < CompiledModules , ( ) > > {
1848
+ self . future . take ( ) . unwrap ( ) . join ( )
1849
+ }
1850
+ }
1851
+
1852
+ impl < B : ExtraBackendMethods > Drop for Coordinator < B > {
1853
+ fn drop ( & mut self ) {
1854
+ if let Some ( future) = self . future . take ( ) {
1855
+ // If we haven't joined yet, signal to the coordinator that it should spawn no more
1856
+ // work, and wait for worker threads to finish.
1857
+ drop ( self . sender . send ( Box :: new ( Message :: CodegenAborted :: < B > ) ) ) ;
1858
+ drop ( future. join ( ) ) ;
1859
+ }
1860
+ }
1861
+ }
1862
+
1831
1863
pub struct OngoingCodegen < B : ExtraBackendMethods > {
1832
1864
pub backend : B ,
1833
1865
pub metadata : EncodedMetadata ,
1834
1866
pub metadata_module : Option < CompiledModule > ,
1835
1867
pub crate_info : CrateInfo ,
1836
- pub coordinator_send : Sender < Box < dyn Any + Send > > ,
1837
1868
pub codegen_worker_receive : Receiver < Message < B > > ,
1838
1869
pub shared_emitter_main : SharedEmitterMain ,
1839
- pub future : thread:: JoinHandle < Result < CompiledModules , ( ) > > ,
1840
1870
pub output_filenames : Arc < OutputFilenames > ,
1871
+ pub coordinator : Coordinator < B > ,
1841
1872
}
1842
1873
1843
1874
impl < B : ExtraBackendMethods > OngoingCodegen < B > {
1844
1875
pub fn join ( self , sess : & Session ) -> ( CodegenResults , FxHashMap < WorkProductId , WorkProduct > ) {
1845
1876
let _timer = sess. timer ( "finish_ongoing_codegen" ) ;
1846
1877
1847
1878
self . shared_emitter_main . check ( sess, true ) ;
1848
- let future = self . future ;
1849
- let compiled_modules = sess. time ( "join_worker_thread" , || match future. join ( ) {
1879
+ let compiled_modules = sess. time ( "join_worker_thread" , || match self . coordinator . join ( ) {
1850
1880
Ok ( Ok ( compiled_modules) ) => compiled_modules,
1851
1881
Ok ( Err ( ( ) ) ) => {
1852
1882
sess. abort_if_errors ( ) ;
@@ -1894,26 +1924,13 @@ impl<B: ExtraBackendMethods> OngoingCodegen<B> {
1894
1924
1895
1925
// These are generally cheap and won't throw off scheduling.
1896
1926
let cost = 0 ;
1897
- submit_codegened_module_to_llvm ( & self . backend , & self . coordinator_send , module, cost) ;
1927
+ submit_codegened_module_to_llvm ( & self . backend , & self . coordinator . sender , module, cost) ;
1898
1928
}
1899
1929
1900
1930
pub fn codegen_finished ( & self , tcx : TyCtxt < ' _ > ) {
1901
1931
self . wait_for_signal_to_codegen_item ( ) ;
1902
1932
self . check_for_errors ( tcx. sess ) ;
1903
- drop ( self . coordinator_send . send ( Box :: new ( Message :: CodegenComplete :: < B > ) ) ) ;
1904
- }
1905
-
1906
- /// Consumes this context indicating that codegen was entirely aborted, and
1907
- /// we need to exit as quickly as possible.
1908
- ///
1909
- /// This method blocks the current thread until all worker threads have
1910
- /// finished, and all worker threads should have exited or be real close to
1911
- /// exiting at this point.
1912
- pub fn codegen_aborted ( self ) {
1913
- // Signal to the coordinator it should spawn no more work and start
1914
- // shutdown.
1915
- drop ( self . coordinator_send . send ( Box :: new ( Message :: CodegenAborted :: < B > ) ) ) ;
1916
- drop ( self . future . join ( ) ) ;
1933
+ drop ( self . coordinator . sender . send ( Box :: new ( Message :: CodegenComplete :: < B > ) ) ) ;
1917
1934
}
1918
1935
1919
1936
pub fn check_for_errors ( & self , sess : & Session ) {
0 commit comments