diff --git a/src/runtest.rs b/src/runtest.rs index 61d8d77..47f9c48 100644 --- a/src/runtest.rs +++ b/src/runtest.rs @@ -33,9 +33,28 @@ use std::io::{self, BufReader}; use std::path::{Path, PathBuf}; use std::process::{Command, Output, ExitStatus, Stdio, Child}; use std::str; +use std::sync::{Arc, Mutex, RwLock}; use extract_gdb_version; +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) { @@ -2343,16 +2362,23 @@ actual:\n\ 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"); - - if let Err(_) = writeln!(file, "{}", self.testpaths.file.display()) { + 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()) + .and_then(|_| file.sync_data()) + .is_err() + { panic!("couldn't write to {}", coverage_file_path.display()); } - } + } } if self.props.run_rustfix {