Acquires an exclusive `flock(2)` on the given lock file path. Opens (or creates) the lock file and calls `flock(LOCK_EX)` in a blocking context. Returns the open `File` whose lifetime controls the lock duration — dropping the file closes the fd and releases the lock.
(lock_path: PathBuf)
| 84 | /// context. Returns the open `File` whose lifetime controls the lock duration — |
| 85 | /// dropping the file closes the fd and releases the lock. |
| 86 | async fn acquire_flock(lock_path: PathBuf) -> std::io::Result<File> { |
| 87 | tokio::task::spawn_blocking(move || { |
| 88 | let file = OpenOptions::new() |
| 89 | .read(true) |
| 90 | .write(true) |
| 91 | .create(true) |
| 92 | .truncate(false) |
| 93 | .open(&lock_path)?; |
| 94 | |
| 95 | // SAFETY: `file.as_raw_fd()` returns a valid fd from the open File above. |
| 96 | // `libc::flock` is a well-defined POSIX syscall that takes a valid fd. |
| 97 | let ret = unsafe { libc::flock(file.as_raw_fd(), libc::LOCK_EX) }; |
| 98 | if ret != 0 { |
| 99 | return Err(std::io::Error::last_os_error()); |
| 100 | } |
| 101 | |
| 102 | Ok(file) |
| 103 | }) |
| 104 | .await |
| 105 | .expect("flock spawn_blocking task panicked") |
| 106 | } |
| 107 | |
| 108 | #[cfg(test)] |
| 109 | mod tests { |