fd_lock/sys/unix/
rw_lock.rs

1use rustix::fd::BorrowedFd;
2use rustix::fs::{flock, FlockOperation};
3use std::io::{self, Error, ErrorKind};
4use std::os::unix::io::AsRawFd;
5
6use super::{RwLockReadGuard, RwLockWriteGuard};
7
8#[derive(Debug)]
9pub struct RwLock<T: AsRawFd> {
10    pub(crate) inner: T,
11}
12
13impl<T: AsRawFd> RwLock<T> {
14    #[inline]
15    pub fn new(inner: T) -> Self {
16        RwLock { inner }
17    }
18
19    #[inline]
20    pub fn write(&mut self) -> io::Result<RwLockWriteGuard<'_, T>> {
21        flock(&self.as_fd(), FlockOperation::LockExclusive)?;
22        Ok(RwLockWriteGuard::new(self))
23    }
24
25    #[inline]
26    pub fn try_write(&mut self) -> Result<RwLockWriteGuard<'_, T>, Error> {
27        flock(&self.as_fd(), FlockOperation::NonBlockingLockExclusive).map_err(|err| match err
28            .kind()
29        {
30            ErrorKind::AlreadyExists => ErrorKind::WouldBlock.into(),
31            _ => Error::from(err),
32        })?;
33        Ok(RwLockWriteGuard::new(self))
34    }
35
36    #[inline]
37    pub fn read(&self) -> io::Result<RwLockReadGuard<'_, T>> {
38        flock(&self.as_fd(), FlockOperation::LockShared)?;
39        Ok(RwLockReadGuard::new(self))
40    }
41
42    #[inline]
43    pub fn try_read(&self) -> Result<RwLockReadGuard<'_, T>, Error> {
44        flock(&self.as_fd(), FlockOperation::NonBlockingLockShared).map_err(|err| {
45            match err.kind() {
46                ErrorKind::AlreadyExists => ErrorKind::WouldBlock.into(),
47                _ => Error::from(err),
48            }
49        })?;
50        Ok(RwLockReadGuard::new(self))
51    }
52
53    #[inline]
54    pub fn into_inner(self) -> T
55    where
56        T: Sized,
57    {
58        self.inner
59    }
60
61    #[inline]
62    pub(crate) fn as_fd(&self) -> BorrowedFd<'_> {
63        // Safety: We assume that `self.inner`'s file descriptor is valid for
64        // at least the lifetime of `self`.
65        //
66        // Once I/O safety is stablized in std, we can switch the public API to
67        // use `AsFd` instead of `AsRawFd` and eliminate this `unsafe` block.
68        unsafe { BorrowedFd::borrow_raw(self.inner.as_raw_fd()) }
69    }
70}