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

(cherry picked from commit 4d84e68dd4)
This commit is contained in:
Johannes Altmanninger
2025-05-20 15:21:00 +02:00
parent 0f8d3a5174
commit 5ccd155177

View File

@@ -44,7 +44,7 @@
};
use bitflags::bitflags;
use libc::{fchmod, fchown, flock, LOCK_EX, LOCK_SH, LOCK_UN};
use libc::{fchmod, fchown, flock, EINTR, LOCK_EX, LOCK_SH, LOCK_UN};
use lru::LruCache;
use nix::{fcntl::OFlag, sys::stat::Mode};
use rand::Rng;
@@ -1353,8 +1353,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(raw_fd, lock_type) };
let (ok, start_time) = loop {
let start_time = SystemTime::now();
if unsafe { flock(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!(
@@ -1367,7 +1374,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.