@@ -10,6 +10,7 @@ use std::process::Stdio;
10
10
use std:: thread;
11
11
use std:: time:: SystemTime ;
12
12
13
+ use super :: death;
13
14
use cargo_test_support:: paths:: { self , CargoPathExt } ;
14
15
use cargo_test_support:: registry:: Package ;
15
16
use cargo_test_support:: { basic_manifest, is_coarse_mtime, project, rustc_host, sleep_ms} ;
@@ -2316,8 +2317,14 @@ LLVM version: 9.0
2316
2317
fn linking_interrupted ( ) {
2317
2318
// Interrupt during the linking phase shouldn't leave test executable as "fresh".
2318
2319
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 ( ) ;
2321
2328
2322
2329
// Create a linker that we can interrupt.
2323
2330
let linker = project ( )
@@ -2326,8 +2333,6 @@ fn linking_interrupted() {
2326
2333
. file (
2327
2334
"src/main.rs" ,
2328
2335
& r#"
2329
- use std::io::Read;
2330
-
2331
2336
fn main() {
2332
2337
// Figure out the output filename.
2333
2338
let output = match std::env::args().find(|a| a.starts_with("/OUT:")) {
@@ -2346,43 +2351,79 @@ fn linking_interrupted() {
2346
2351
std::fs::write(&output, "").unwrap();
2347
2352
// Tell the test that we are ready to be interrupted.
2348
2353
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) );
2351
2356
}
2352
2357
"#
2353
- . replace ( "__ADDR__" , & addr . to_string ( ) ) ,
2358
+ . replace ( "__ADDR__" , & link_addr . to_string ( ) ) ,
2354
2359
)
2355
2360
. build ( ) ;
2356
2361
linker. cargo ( "build" ) . run ( ) ;
2357
2362
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
+
2358
2389
// Build it once so that the fingerprint gets saved to disk.
2359
2390
let p = project ( )
2360
2391
. file ( "src/lib.rs" , "" )
2361
2392
. file ( "tests/t1.rs" , "" )
2362
2393
. build ( ) ;
2363
2394
p. cargo ( "test --test t1 --no-run" ) . run ( ) ;
2395
+
2364
2396
// Make a change, start a build, then interrupt it.
2365
2397
p. change_file ( "src/lib.rs" , "// modified" ) ;
2366
2398
let linker_env = format ! (
2367
2399
"CARGO_TARGET_{}_LINKER" ,
2368
2400
rustc_host( ) . to_uppercase( ) . replace( '-' , "_" )
2369
2401
) ;
2402
+ // NOTE: This assumes that the paths to the linker or rustc are not in the
2403
+ // fingerprint. But maybe they should be?
2370
2404
let mut cmd = p
2371
2405
. cargo ( "test --test t1 --no-run" )
2372
2406
. env ( & linker_env, linker. bin ( "linker" ) )
2407
+ . env ( "RUSTC" , rustc. bin ( "rustc-waiter" ) )
2373
2408
. build_command ( ) ;
2374
2409
let mut child = cmd
2375
2410
. stdout ( Stdio :: null ( ) )
2376
2411
. stderr ( Stdio :: null ( ) )
2412
+ . env ( "__CARGO_TEST_SETSID_PLEASE_DONT_USE_ELSEWHERE" , "1" )
2377
2413
. spawn ( )
2378
2414
. unwrap ( ) ;
2415
+ // Wait for rustc to start.
2416
+ let mut rustc_conn = rustc_listener. accept ( ) . unwrap ( ) . 0 ;
2379
2417
// Wait for linking to start.
2380
- let mut conn = listener . accept ( ) . unwrap ( ) . 0 ;
2418
+ drop ( link_listener . accept ( ) . unwrap ( ) ) ;
2381
2419
2382
2420
// 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) ) ;
2386
2427
2387
2428
// Build again, shouldn't be fresh.
2388
2429
p. cargo ( "test --test t1" )
0 commit comments