Retry history file flock() on EINTR

When locking the uvar file, we retry whenever flock() fails with EINTR
(e.g. due to ctrl-c).

But not when locking the history file.  This seems wrong; all other libc
functions in the "history_file" code path do retry.

Fix that. In future we should extract a function.

Note that there are other inconsistencies; flock_uvar_file() does not
shy away from remote file systems and does not respect ABANDONED_LOCKING.
This means that empirically probably neither are necessary; let's make things
consistent in future.

See https://github.com/fish-shell/fish-shell/pull/11492#discussion_r2095096200
Might help #10300
This commit is contained in:
Johannes Altmanninger
2025-05-20 15:21:00 +02:00
parent 285a810814
commit 4d84e68dd4

View File

@@ -42,7 +42,7 @@
};
use bitflags::bitflags;
use libc::{fchown, flock, LOCK_EX, LOCK_SH, LOCK_UN};
use libc::{fchown, flock, EINTR, LOCK_EX, LOCK_SH, LOCK_UN};
use lru::LruCache;
use nix::{fcntl::OFlag, sys::stat::Mode};
use rand::Rng;
@@ -1359,8 +1359,15 @@ unsafe fn maybe_lock_file(file: &mut File, lock_type: libc::c_int) -> bool {
return false;
}
let start_time = SystemTime::now();
let retval = unsafe { flock(file.as_raw_fd(), lock_type) };
let (ok, start_time) = loop {
let start_time = SystemTime::now();
if unsafe { flock(file.as_raw_fd(), lock_type) } == -1 {
if errno::errno().0 != EINTR {
break (false, start_time);
}
}
break (true, start_time);
};
if let Ok(duration) = start_time.elapsed() {
if duration > Duration::from_millis(250) {
FLOG!(
@@ -1373,7 +1380,7 @@ unsafe fn maybe_lock_file(file: &mut File, lock_type: libc::c_int) -> bool {
ABANDONED_LOCKING.store(true);
}
}
retval != -1
ok
}
/// Unlock a history file.