diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 26730fcec4cec..546ac5ae296d5 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -30,6 +30,7 @@ use std::io::{self, BufReader}; use std::path::{Path, PathBuf}; use std::process::{Child, Command, ExitStatus, Output, Stdio}; use std::str; +use std::sync::{Arc, Mutex, RwLock}; use glob::glob; use lazy_static::lazy_static; @@ -73,6 +74,21 @@ fn disable_error_reporting R, R>(f: F) -> R { f() } +fn get_or_create_coverage_file(path: &Path, create: impl FnOnce() -> File) -> Arc> { + lazy_static::lazy_static! { + static ref COVERAGE_FILE_LOCKS: RwLock>>> = RwLock::new(HashMap::new()); + } + + { + let locks = COVERAGE_FILE_LOCKS.read().unwrap(); + locks.get(path).map(Arc::clone) + } + .unwrap_or_else(|| { + let mut locks = COVERAGE_FILE_LOCKS.write().unwrap(); + locks.entry(path.to_path_buf()).or_insert_with(|| Arc::new(Mutex::new(create()))).clone() + }) +} + /// The name of the environment variable that holds dynamic library locations. pub fn dylib_env_var() -> &'static str { if cfg!(windows) { @@ -3237,13 +3253,20 @@ impl<'test> TestCx<'test> { coverage_file_path.push("rustfix_missing_coverage.txt"); debug!("coverage_file_path: {}", coverage_file_path.display()); - let mut file = OpenOptions::new() - .create(true) - .append(true) - .open(coverage_file_path.as_path()) - .expect("could not create or open file"); + let file_ref = get_or_create_coverage_file(&coverage_file_path, || { + OpenOptions::new() + .create(true) + .write(true) + .truncate(true) + .open(coverage_file_path.as_path()) + .expect("could not create or open file") + }); + let mut file = file_ref.lock().unwrap(); - if writeln!(file, "{}", self.testpaths.file.display()).is_err() { + if writeln!(file, "{}", self.testpaths.file.display()) + .and_then(|_| file.sync_data()) + .is_err() + { panic!("couldn't write to {}", coverage_file_path.display()); } }