@@ -10,6 +10,7 @@ use std::process::Stdio;
1010use std:: thread;
1111use std:: time:: SystemTime ;
1212
13+ use super :: death;
1314use cargo_test_support:: paths:: { self , CargoPathExt } ;
1415use cargo_test_support:: registry:: Package ;
1516use cargo_test_support:: { basic_manifest, is_coarse_mtime, project, rustc_host, sleep_ms} ;
@@ -2316,8 +2317,14 @@ LLVM version: 9.0
23162317fn linking_interrupted ( ) {
23172318 // Interrupt during the linking phase shouldn't leave test executable as "fresh".
23182319
2319- let listener = TcpListener :: bind ( "127.0.0.1:0" ) . unwrap ( ) ;
2320- let addr = listener. local_addr ( ) . unwrap ( ) ;
2320+ // This is used to detect when linking starts, then to pause the linker so
2321+ // that the test can kill cargo.
2322+ let link_listener = TcpListener :: bind ( "127.0.0.1:0" ) . unwrap ( ) ;
2323+ let link_addr = link_listener. local_addr ( ) . unwrap ( ) ;
2324+
2325+ // This is used to detect when rustc exits.
2326+ let rustc_listener = TcpListener :: bind ( "127.0.0.1:0" ) . unwrap ( ) ;
2327+ let rustc_addr = rustc_listener. local_addr ( ) . unwrap ( ) ;
23212328
23222329 // Create a linker that we can interrupt.
23232330 let linker = project ( )
@@ -2326,8 +2333,6 @@ fn linking_interrupted() {
23262333 . file (
23272334 "src/main.rs" ,
23282335 & r#"
2329- use std::io::Read;
2330-
23312336 fn main() {
23322337 // Figure out the output filename.
23332338 let output = match std::env::args().find(|a| a.starts_with("/OUT:")) {
@@ -2346,43 +2351,79 @@ fn linking_interrupted() {
23462351 std::fs::write(&output, "").unwrap();
23472352 // Tell the test that we are ready to be interrupted.
23482353 let mut socket = std::net::TcpStream::connect("__ADDR__").unwrap();
2349- // Wait for the test to tell us to exit .
2350- let _ = socket.read(&mut [0; 1] );
2354+ // Wait for the test to kill us.
2355+ std::thread::sleep(std::time::Duration::new(60, 0) );
23512356 }
23522357 "#
2353- . replace ( "__ADDR__" , & addr . to_string ( ) ) ,
2358+ . replace ( "__ADDR__" , & link_addr . to_string ( ) ) ,
23542359 )
23552360 . build ( ) ;
23562361 linker. cargo ( "build" ) . run ( ) ;
23572362
2363+ // Create a wrapper around rustc that will tell us when rustc is finished.
2364+ let rustc = project ( )
2365+ . at ( "rustc-waiter" )
2366+ . file ( "Cargo.toml" , & basic_manifest ( "rustc-waiter" , "1.0.0" ) )
2367+ . file (
2368+ "src/main.rs" ,
2369+ & r#"
2370+ fn main() {
2371+ let mut conn = None;
2372+ // Check for a normal build (not -vV or --print).
2373+ if std::env::args().any(|arg| arg == "t1") {
2374+ // Tell the test that rustc has started.
2375+ conn = Some(std::net::TcpStream::connect("__ADDR__").unwrap());
2376+ }
2377+ let status = std::process::Command::new("rustc")
2378+ .args(std::env::args().skip(1))
2379+ .status()
2380+ .expect("rustc to run");
2381+ std::process::exit(status.code().unwrap_or(1));
2382+ }
2383+ "#
2384+ . replace ( "__ADDR__" , & rustc_addr. to_string ( ) ) ,
2385+ )
2386+ . build ( ) ;
2387+ rustc. cargo ( "build" ) . run ( ) ;
2388+
23582389 // Build it once so that the fingerprint gets saved to disk.
23592390 let p = project ( )
23602391 . file ( "src/lib.rs" , "" )
23612392 . file ( "tests/t1.rs" , "" )
23622393 . build ( ) ;
23632394 p. cargo ( "test --test t1 --no-run" ) . run ( ) ;
2395+
23642396 // Make a change, start a build, then interrupt it.
23652397 p. change_file ( "src/lib.rs" , "// modified" ) ;
23662398 let linker_env = format ! (
23672399 "CARGO_TARGET_{}_LINKER" ,
23682400 rustc_host( ) . to_uppercase( ) . replace( '-' , "_" )
23692401 ) ;
2402+ // NOTE: This assumes that the paths to the linker or rustc are not in the
2403+ // fingerprint. But maybe they should be?
23702404 let mut cmd = p
23712405 . cargo ( "test --test t1 --no-run" )
23722406 . env ( & linker_env, linker. bin ( "linker" ) )
2407+ . env ( "RUSTC" , rustc. bin ( "rustc-waiter" ) )
23732408 . build_command ( ) ;
23742409 let mut child = cmd
23752410 . stdout ( Stdio :: null ( ) )
23762411 . stderr ( Stdio :: null ( ) )
2412+ . env ( "__CARGO_TEST_SETSID_PLEASE_DONT_USE_ELSEWHERE" , "1" )
23772413 . spawn ( )
23782414 . unwrap ( ) ;
2415+ // Wait for rustc to start.
2416+ let mut rustc_conn = rustc_listener. accept ( ) . unwrap ( ) . 0 ;
23792417 // Wait for linking to start.
2380- let mut conn = listener . accept ( ) . unwrap ( ) . 0 ;
2418+ drop ( link_listener . accept ( ) . unwrap ( ) ) ;
23812419
23822420 // Interrupt the child.
2383- child. kill ( ) . unwrap ( ) ;
2384- // Note: rustc and the linker are still running, let them exit here.
2385- conn. write ( b"X" ) . unwrap ( ) ;
2421+ death:: ctrl_c ( & mut child) ;
2422+ assert ! ( !child. wait( ) . unwrap( ) . success( ) ) ;
2423+ // Wait for rustc to exit. If we don't wait, then the command below could
2424+ // start while rustc is still being torn down.
2425+ let mut buf = [ 0 ] ;
2426+ drop ( rustc_conn. read_exact ( & mut buf) ) ;
23862427
23872428 // Build again, shouldn't be fresh.
23882429 p. cargo ( "test --test t1" )
0 commit comments