-
Notifications
You must be signed in to change notification settings - Fork 682
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added Flock
object for automatic unlock on drop.
#2170
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's little point in wrapping a RawFd
, since RawFd
implements Copy
. It would be way too easy to use accidentally use the RawFd
after dropping the lock. If anything, it should wrap OwnedFd
. And if we're going to do this, then we should make the flock
function private.
I kinda think wrapping an fn main() {
let mut file = File::create("foo").unwrap();
let flock_guard = Flock::lock(file.into(), FlockArg::LockExclusive).unwrap();
// error[E0382]: borrow of moved value: `file`
file.write(b"bar").unwrap();
// guard dropped here
} I have to convert the What about we use a pub struct Flock<'fd>(BorrowedFd<'fd>);
impl<'fd> Drop for Flock<'fd> {
fn drop(&mut self) {
_ = flock(self.0.as_raw_fd(), FlockArg::Unlock);
}
}
impl<'fd> Flock<'fd> {
pub fn lock(fd: BorrowedFd<'fd>, args: FlockArg) -> anyhow::Result<Self> {
flock(fd.as_raw_fd(), args)?;
Ok(Self(fd))
}
} Though this won't make the above code compile either: let mut file = File::create("foo").unwrap();
let flock_guard =
Flock::lock(file.as_fd(), FlockArg::LockExclusive).unwrap();
// E0502: cannot borrow `file` as mutable because it is also borrowed as immutable
file.write(b"bar").unwrap(); But we can do this: let file = File::create("foo").unwrap();
let flock_guard =
Flock::lock(file.as_fd(), FlockArg::LockExclusive).unwrap();
// compiles without any issue
(&file).write(b"bar").unwrap(); |
ref: #1750 |
If pub struct Flock(File);
impl Drop for Flock {
fn drop(&mut self) {
_ = flock(self.0.as_raw_fd(), FlockArg::Unlock);
}
}
impl Deref for Flock {
type Target = File;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for Flock {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl Flock {
pub fn lock(fd: File, args: FlockArg) -> Result<Self> {
flock(fd.as_raw_fd(), args)?;
Ok(Self(fd))
}
pub fn unlock(self) -> File {
_ = flock(self.0.as_raw_fd(), FlockArg::Unlock);
self.0
}
} |
Yeah, I agree this is the Rusty way to implement it
|
Could you provide some examples or cite what other things it can be used on? I'm looking through a bunch of linux kernel and posix docs and they only specifically call out "files" (and local VFS files at that). The brute force way is to just open every type of file descriptor that we can think of and just see what works and what doesn't, though I guess for the purposes of this we just need 2 valid to make the I could understand an argument that |
Just checked the FreeBSD manual since this syscall is not POSIX but comes from BSD implementations:
This is not specified in the Linux manual, and I can call #include <stdio.h>
#include <stdlib.h>
#include <sys/file.h>
#include <unistd.h>
int main(void) {
int fd[2] = {0};
int res = pipe(fd);
if (res != 0) {
perror("pipe(2)");
exit(EXIT_FAILURE);
}
res = flock(fd[0], LOCK_EX);
if (res != 0) {
perror("flock(2)");
exit(EXIT_FAILURE);
}
printf("flock acquired on a pipe fd\n");
exit(EXIT_SUCCESS);
} $ uname -a
Linux fedora 6.5.9-300.fc39.x86_64 #1 SMP PREEMPT_DYNAMIC Wed Oct 25 21:39:20 UTC 2023 x86_64 GNU/Linux
$ gcc main.c
$ ./a.out
flock acquired on a pipe fd
I agree that most manuals of
but for systems that don't prohibit this, given that |
So we can't wrap |
I think everything is good to go, but looks like the gnu test had a random failure (it succeeded in the previous runs). |
If we want to implement If we want it to be generic without pulling third-party dependencies, i.e. unsafe impl<T: AsRawFd> Flockable for T { } Then the unsafe mark seems to be meaningless |
BTW, we have migrated our most CI tasks to GHA, the CI in this PR is in a mixed, intermediate state, rebasing your branch should resolve it |
Co-authored-by: SteveLauC <stevelauc@outlook.com>
I don't think the intent is to pull in tokio (would probably cause circular dependency anyhow), more that tokio would be able to implement it on their end, like so: unsafe impl nix::fcntl::Flockable for tokio::fs::File {}; Thus the trait is "generic" because anyone can implement it (it is a public trait after all). |
… period, added EINVAL case if the unlock operation is given to `Flock::lock()`.
…unlock()` is used.
Looks like the extra failures were "spurious network errors", then the one expected error with |
We are fixing this, once that PR is merged, rebasing your branch to re-run the jobs should get them all resolved |
Gentle ping on the author @coderBlitz, would you like to finish this PR? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
What does this PR do
In the spirit of RAII, created the
Flock
newtype to simplifyflock
lock handling. Users can pass around an explicit representation of a held lock, automatically unlocking once it goes out of scope.Checklist:
CONTRIBUTING.md