Skip to content

Commit 01648b9

Browse files
committed
Add a wrapper to wait for rustc to exit.
1 parent ca085e9 commit 01648b9

File tree

2 files changed

+52
-28
lines changed

2 files changed

+52
-28
lines changed

tests/testsuite/death.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,14 +88,14 @@ fn ctrl_c_kills_everyone() {
8888
}
8989

9090
#[cfg(unix)]
91-
fn ctrl_c(child: &mut Child) {
91+
pub fn ctrl_c(child: &mut Child) {
9292
let r = unsafe { libc::kill(-(child.id() as i32), libc::SIGINT) };
9393
if r < 0 {
9494
panic!("failed to kill: {}", io::Error::last_os_error());
9595
}
9696
}
9797

9898
#[cfg(windows)]
99-
fn ctrl_c(child: &mut Child) {
99+
pub fn ctrl_c(child: &mut Child) {
100100
child.kill().unwrap();
101101
}

tests/testsuite/freshness.rs

Lines changed: 50 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use std::process::Stdio;
1010
use std::thread;
1111
use std::time::SystemTime;
1212

13+
use super::death;
1314
use cargo_test_support::paths::{self, CargoPathExt};
1415
use cargo_test_support::registry::Package;
1516
use cargo_test_support::{basic_manifest, is_coarse_mtime, project, rustc_host, sleep_ms};
@@ -2318,8 +2319,12 @@ fn linking_interrupted() {
23182319

23192320
// This is used to detect when linking starts, then to pause the linker so
23202321
// that the test can kill cargo.
2321-
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
2322-
let addr = listener.local_addr().unwrap();
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();
23232328

23242329
// Create a linker that we can interrupt.
23252330
let linker = project()
@@ -2328,8 +2333,6 @@ fn linking_interrupted() {
23282333
.file(
23292334
"src/main.rs",
23302335
&r#"
2331-
use std::io::Read;
2332-
23332336
fn main() {
23342337
// Figure out the output filename.
23352338
let output = match std::env::args().find(|a| a.starts_with("/OUT:")) {
@@ -2348,58 +2351,79 @@ fn linking_interrupted() {
23482351
std::fs::write(&output, "").unwrap();
23492352
// Tell the test that we are ready to be interrupted.
23502353
let mut socket = std::net::TcpStream::connect("__ADDR__").unwrap();
2351-
// Wait for the test to tell us to exit.
2352-
let _ = socket.read(&mut [0; 1]);
2354+
// Wait for the test to kill us.
2355+
std::thread::sleep(std::time::Duration::new(60, 0));
23532356
}
23542357
"#
2355-
.replace("__ADDR__", &addr.to_string()),
2358+
.replace("__ADDR__", &link_addr.to_string()),
23562359
)
23572360
.build();
23582361
linker.cargo("build").run();
23592362

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+
23602389
// Build it once so that the fingerprint gets saved to disk.
23612390
let p = project()
23622391
.file("src/lib.rs", "")
23632392
.file("tests/t1.rs", "")
23642393
.build();
23652394
p.cargo("test --test t1 --no-run").run();
2395+
23662396
// Make a change, start a build, then interrupt it.
23672397
p.change_file("src/lib.rs", "// modified");
23682398
let linker_env = format!(
23692399
"CARGO_TARGET_{}_LINKER",
23702400
rustc_host().to_uppercase().replace('-', "_")
23712401
);
2372-
// NOTE: This assumes that the path to the linker is not in the
2373-
// fingerprint. But maybe it should be?
2402+
// NOTE: This assumes that the paths to the linker or rustc are not in the
2403+
// fingerprint. But maybe they should be?
23742404
let mut cmd = p
23752405
.cargo("test --test t1 --no-run")
23762406
.env(&linker_env, linker.bin("linker"))
2407+
.env("RUSTC", rustc.bin("rustc-waiter"))
23772408
.build_command();
23782409
let mut child = cmd
23792410
.stdout(Stdio::null())
23802411
.stderr(Stdio::null())
2412+
.env("__CARGO_TEST_SETSID_PLEASE_DONT_USE_ELSEWHERE", "1")
23812413
.spawn()
23822414
.unwrap();
2415+
// Wait for rustc to start.
2416+
let mut rustc_conn = rustc_listener.accept().unwrap().0;
23832417
// Wait for linking to start.
2384-
let mut conn = listener.accept().unwrap().0;
2418+
drop(link_listener.accept().unwrap());
23852419

23862420
// Interrupt the child.
2387-
child.kill().unwrap();
2388-
child.wait().unwrap();
2389-
// Note: rustc and the linker may still be running because we didn't kill
2390-
// the entire process group. Normally, when a user hits Ctrl-C, everything
2391-
// is killed. However, setting up process groups in a cross-platform test
2392-
// is a pain, and there's no easy way to know when everything has been
2393-
// killed. This write will tell them to exit, pretending that they died
2394-
// before finishing. Ignore the error, because (sometimes?) on Windows
2395-
// everything is already killed.
2396-
let _ = conn.write(b"X");
2397-
// Sleep a bit to allow rustc to clean up and exit. I have seen some race
2398-
// conditions on macOS where clang dies with `no such
2399-
// file...t1-HASH.rcgu.o`. I think what is happening is that the old rustc
2400-
// process is still running, and deletes the `*.o` files while the command
2401-
// below is trying to write them. Not sure if that is macOS-specific.
2402-
std::thread::sleep(std::time::Duration::new(2, 0));
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));
24032427

24042428
// Build again, shouldn't be fresh.
24052429
p.cargo("test --test t1")

0 commit comments

Comments
 (0)