@@ -37,6 +37,7 @@ use rustc_target::spec::{MergeFunctions, SanitizerSet};
3737use std:: any:: Any ;
3838use std:: fs;
3939use std:: io;
40+ use std:: marker:: PhantomData ;
4041use std:: mem;
4142use std:: path:: { Path , PathBuf } ;
4243use std:: str;
@@ -475,10 +476,13 @@ pub fn start_async_codegen<B: ExtraBackendMethods>(
475476 metadata_module,
476477 crate_info,
477478
478- coordinator_send,
479479 codegen_worker_receive,
480480 shared_emitter_main,
481- future : coordinator_thread,
481+ coordinator : Coordinator {
482+ sender : coordinator_send,
483+ future : Some ( coordinator_thread) ,
484+ phantom : PhantomData ,
485+ } ,
482486 output_filenames : tcx. output_filenames ( ( ) ) . clone ( ) ,
483487 }
484488}
@@ -1273,6 +1277,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
12731277 // work to be done.
12741278 while !codegen_done
12751279 || running > 0
1280+ || main_thread_worker_state == MainThreadWorkerState :: LLVMing
12761281 || ( !codegen_aborted
12771282 && !( work_items. is_empty ( )
12781283 && needs_fat_lto. is_empty ( )
@@ -1470,14 +1475,12 @@ fn start_executing_work<B: ExtraBackendMethods>(
14701475 if !cgcx. opts . unstable_opts . no_parallel_llvm {
14711476 helper. request_token ( ) ;
14721477 }
1473- assert ! ( !codegen_aborted) ;
14741478 assert_eq ! ( main_thread_worker_state, MainThreadWorkerState :: Codegenning ) ;
14751479 main_thread_worker_state = MainThreadWorkerState :: Idle ;
14761480 }
14771481
14781482 Message :: CodegenComplete => {
14791483 codegen_done = true ;
1480- assert ! ( !codegen_aborted) ;
14811484 assert_eq ! ( main_thread_worker_state, MainThreadWorkerState :: Codegenning ) ;
14821485 main_thread_worker_state = MainThreadWorkerState :: Idle ;
14831486 }
@@ -1489,10 +1492,8 @@ fn start_executing_work<B: ExtraBackendMethods>(
14891492 // then conditions above will ensure no more work is spawned but
14901493 // we'll keep executing this loop until `running` hits 0.
14911494 Message :: CodegenAborted => {
1492- assert ! ( !codegen_aborted) ;
14931495 codegen_done = true ;
14941496 codegen_aborted = true ;
1495- assert_eq ! ( main_thread_worker_state, MainThreadWorkerState :: Codegenning ) ;
14961497 }
14971498 Message :: Done { result : Ok ( compiled_module) , worker_id } => {
14981499 free_worker ( worker_id) ;
@@ -1532,13 +1533,20 @@ fn start_executing_work<B: ExtraBackendMethods>(
15321533 Message :: Done { result : Err ( None ) , worker_id : _ } => {
15331534 bug ! ( "worker thread panicked" ) ;
15341535 }
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 ;
15371541 }
15381542 Message :: CodegenItem => bug ! ( "the coordinator should not receive codegen requests" ) ,
15391543 }
15401544 }
15411545
1546+ if codegen_aborted {
1547+ return Err ( ( ) ) ;
1548+ }
1549+
15421550 let needs_link = mem:: take ( & mut needs_link) ;
15431551 if !needs_link. is_empty ( ) {
15441552 assert ! ( compiled_modules. is_empty( ) ) ;
@@ -1828,25 +1836,47 @@ impl SharedEmitterMain {
18281836 }
18291837}
18301838
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+
18311863pub struct OngoingCodegen < B : ExtraBackendMethods > {
18321864 pub backend : B ,
18331865 pub metadata : EncodedMetadata ,
18341866 pub metadata_module : Option < CompiledModule > ,
18351867 pub crate_info : CrateInfo ,
1836- pub coordinator_send : Sender < Box < dyn Any + Send > > ,
18371868 pub codegen_worker_receive : Receiver < Message < B > > ,
18381869 pub shared_emitter_main : SharedEmitterMain ,
1839- pub future : thread:: JoinHandle < Result < CompiledModules , ( ) > > ,
18401870 pub output_filenames : Arc < OutputFilenames > ,
1871+ pub coordinator : Coordinator < B > ,
18411872}
18421873
18431874impl < B : ExtraBackendMethods > OngoingCodegen < B > {
18441875 pub fn join ( self , sess : & Session ) -> ( CodegenResults , FxHashMap < WorkProductId , WorkProduct > ) {
18451876 let _timer = sess. timer ( "finish_ongoing_codegen" ) ;
18461877
18471878 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 ( ) {
18501880 Ok ( Ok ( compiled_modules) ) => compiled_modules,
18511881 Ok ( Err ( ( ) ) ) => {
18521882 sess. abort_if_errors ( ) ;
@@ -1894,26 +1924,13 @@ impl<B: ExtraBackendMethods> OngoingCodegen<B> {
18941924
18951925 // These are generally cheap and won't throw off scheduling.
18961926 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) ;
18981928 }
18991929
19001930 pub fn codegen_finished ( & self , tcx : TyCtxt < ' _ > ) {
19011931 self . wait_for_signal_to_codegen_item ( ) ;
19021932 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 > ) ) ) ;
19171934 }
19181935
19191936 pub fn check_for_errors ( & self , sess : & Session ) {
0 commit comments