mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-10-16 04:33:16 +00:00
Replace PID-based liveness probing in `live_marker_count` with flock
advisory-lock presence detection. Each test process opens
`<session_root>/clients/<pid>` once, holds LOCK_SH for the lifetime
of any live TestContext in the process, and releases it explicitly
when `cleanup_session_root` fires at refcount zero. Reapers probe with
LOCK_EX | LOCK_NB: success means the previous owner is gone (normal
exit, panic, SIGKILL, or zombie — the kernel releases advisory locks
at process exit in every case) and the stale marker is removed.
Compared to the PID check this was replacing:
- Handles PID recycling correctly (the new holder does not inherit
the previous owner's advisory lock).
- Handles zombies correctly without shelling out to `ps`.
- Costs one open + one flock per peer, ~50 us on macOS.
The marker handle is stored in a process-scoped
`Mutex<Option<(PathBuf, File)>>` so it can be released and
reacquired across the drop-to-zero / rise-from-zero cycles that
`session_refs` already implements. Storing the path alongside the
handle enables a debug assertion that the process never drifts
between session roots.
`ClientMarker` and its serde plumbing are removed; the marker file is
now empty, its existence and lock state carrying the signal.
Full workspace wall-clock after A+B+C: 13.3–13.6 s, down from 20–25 s
on HEAD before the fix and comparable to the 14 s Friday baseline
despite the intervening +85 tests.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
94 lines
2.8 KiB
Rust
94 lines
2.8 KiB
Rust
use std::fs::File;
|
|
use std::io;
|
|
use std::os::unix::io::AsRawFd;
|
|
|
|
/// Try to acquire an exclusive (write) lock on `file` without blocking.
|
|
///
|
|
/// Returns `Ok(true)` if the lock was acquired, `Ok(false)` if another
|
|
/// process/fd already holds the lock, and `Err` for unexpected errors.
|
|
pub fn try_flock_exclusive(file: &File) -> io::Result<bool> {
|
|
// SAFETY: flock() on a valid fd is safe; LOCK_NB makes it non-blocking.
|
|
let ret = unsafe { libc::flock(file.as_raw_fd(), libc::LOCK_EX | libc::LOCK_NB) };
|
|
if ret == 0 {
|
|
Ok(true)
|
|
} else {
|
|
let err = io::Error::last_os_error();
|
|
match err.raw_os_error() {
|
|
Some(libc::EWOULDBLOCK) => Ok(false),
|
|
_ => Err(err),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Try to acquire a shared (read) lock on `file` without blocking.
|
|
///
|
|
/// Returns `Ok(true)` if the lock was acquired, `Ok(false)` if another
|
|
/// process/fd already holds an incompatible lock, and `Err` for unexpected
|
|
/// errors.
|
|
pub fn try_flock_shared(file: &File) -> io::Result<bool> {
|
|
// SAFETY: flock() on a valid fd is safe; LOCK_NB makes it non-blocking.
|
|
let ret = unsafe { libc::flock(file.as_raw_fd(), libc::LOCK_SH | libc::LOCK_NB) };
|
|
if ret == 0 {
|
|
Ok(true)
|
|
} else {
|
|
let err = io::Error::last_os_error();
|
|
match err.raw_os_error() {
|
|
Some(libc::EWOULDBLOCK) => Ok(false),
|
|
_ => Err(err),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Release any lock held on `file`.
|
|
pub fn flock_unlock(file: &File) -> io::Result<()> {
|
|
// SAFETY: flock() with LOCK_UN on a valid fd is safe.
|
|
let ret = unsafe { libc::flock(file.as_raw_fd(), libc::LOCK_UN) };
|
|
if ret == 0 {
|
|
Ok(())
|
|
} else {
|
|
Err(io::Error::last_os_error())
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
#[expect(
|
|
clippy::disallowed_methods,
|
|
reason = "tests exercise sync flock semantics on real temp files; uses std::fs::File directly"
|
|
)]
|
|
mod tests {
|
|
use std::fs::File;
|
|
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn acquire_exclusive_lock() {
|
|
let dir = tempfile::tempdir().unwrap();
|
|
let path = dir.path().join("lock");
|
|
let file = File::create(&path).unwrap();
|
|
|
|
let acquired = try_flock_exclusive(&file).unwrap();
|
|
assert!(acquired);
|
|
}
|
|
|
|
#[test]
|
|
fn unlock_then_reacquire() {
|
|
let dir = tempfile::tempdir().unwrap();
|
|
let path = dir.path().join("lock");
|
|
let file = File::create(&path).unwrap();
|
|
|
|
assert!(try_flock_exclusive(&file).unwrap());
|
|
flock_unlock(&file).unwrap();
|
|
assert!(try_flock_exclusive(&file).unwrap());
|
|
}
|
|
|
|
#[test]
|
|
fn second_fd_blocked() {
|
|
let dir = tempfile::tempdir().unwrap();
|
|
let path = dir.path().join("lock");
|
|
let file1 = File::create(&path).unwrap();
|
|
let file2 = File::open(&path).unwrap();
|
|
|
|
assert!(try_flock_exclusive(&file1).unwrap());
|
|
assert!(!try_flock_exclusive(&file2).unwrap());
|
|
}
|
|
}
|