Add mutex around flock on Cygwin

Issue #11933 stems from Cygwin's flock implementation not being thread
safe. Previous code fixed the worst behavior (deadlock), at least in
some circumstance but still failed the history tests.

This new workaround correctly make flock usage thread safe by surrounding
it with a mutex lock.
The failing test can now pass and is much faster (5s instead of 15 on
my machine)

Upstream bug report: https://cygwin.com/pipermail/cygwin/2025-November/258963.html

Closes #12068
Closes #11933
This commit is contained in:
Nahor
2025-11-15 08:49:24 -08:00
committed by Johannes Altmanninger
parent d716b32bed
commit 125fc142ba
2 changed files with 13 additions and 14 deletions

View File

@@ -144,17 +144,21 @@ pub fn new(locking_mode: LockingMode, file_path: &wstr) -> std::io::Result<Self>
// This is required to avoid racing modifications by other threads/processes.
let dir_fd = wopen_cloexec(dir_path, OFlag::O_RDONLY, Mode::empty())?;
// Try locking the directory. Retry if locking was interrupted.
while unsafe { libc::flock(dir_fd.as_raw_fd(), locking_mode.flock_op()) } == -1 {
let err = std::io::Error::last_os_error();
if err.kind() != std::io::ErrorKind::Interrupted {
return Err(err);
{
// Cygwin's `flock` is currently not thread safe (#11933)
#[cfg(cygwin)]
static FLOCK_LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());
#[cfg(cygwin)]
let _lock = FLOCK_LOCK.lock().unwrap();
// Try locking the directory. Retry if locking was interrupted.
while unsafe { libc::flock(dir_fd.as_raw_fd(), locking_mode.flock_op()) } == -1 {
let err = std::io::Error::last_os_error();
if err.kind() != std::io::ErrorKind::Interrupted {
return Err(err);
}
}
}
#[cfg(cygwin)]
// Prevents error 14 "Bad Addr" on Windows (#11933). If the error happens
// the process appears deadlocked
std::thread::sleep(std::time::Duration::from_nanos(1));
// Open the data file
let data_file = wopen_cloexec(file_path, locking_mode.file_flags(), LOCKED_FILE_MODE)?;

View File

@@ -2015,11 +2015,6 @@ fn pound_on_history(item_count: usize, idx: usize) -> Arc<History> {
fn test_history_races() {
let _cleanup = test_init();
// Fail nearly every time on Cygwin (probably caused by flock issue, see #11933)
if cfg!(cygwin) {
return;
}
let tmp_path = std::env::current_dir()
.unwrap()
.join("history-races-test-balloon");