Skip to content

Commit

Permalink
Use the new I/O safety traits, using rustix
Browse files Browse the repository at this point in the history
Switch public APIs from `AsRawFd`/`AsRawHandle` to the new I/O safety
traits `AsFd`/`AsHandle`. On Unix platforms, use rustix to avoid
manipulating raw file descriptors altogether.
  • Loading branch information
sunfishcode committed Jan 14, 2022
1 parent 3bc0dcd commit 4bb9c47
Show file tree
Hide file tree
Showing 9 changed files with 38 additions and 42 deletions.
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,8 @@ features = [
[target.'cfg(unix)'.dependencies]
rustix = "0.31.3"

[target.'cfg(windows)'.dependencies]
io-lifetimes = { version = "0.4.0", default-features = false }

[dev-dependencies]
tempfile = "3.0.8"
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#![forbid(future_incompatible)]
#![deny(missing_debug_implementations, nonstandard_style)]
#![cfg_attr(doc, warn(missing_docs, rustdoc::missing_doc_code_examples))]
#![cfg_attr(io_lifetimes_use_std, feature(io_safety))]

mod read_guard;
mod rw_lock;
Expand Down
4 changes: 2 additions & 2 deletions src/sys/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ cfg_if! {
if #[cfg(unix)] {
mod unix;
pub use unix::*;
pub(crate) use std::os::unix::prelude::AsRawFd as AsRaw;
pub(crate) use rustix::fd::AsFd as AsRaw;
} else if #[cfg(windows)] {
mod windows;
pub use windows::*;
#[doc(no_inline)]
pub(crate) use std::os::windows::prelude::AsRawHandle as AsRaw;
pub(crate) use io_lifetimes::AsHandle as AsRaw;
} else {
mod unsupported;
pub use unsupported;
Expand Down
10 changes: 5 additions & 5 deletions src/sys/unix/read_guard.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
use rustix::fd::AsFd;
use rustix::fs::{flock, FlockOperation};
use std::ops;
use std::os::unix::io::AsRawFd;

use super::RwLock;

#[derive(Debug)]
pub struct RwLockReadGuard<'lock, T: AsRawFd> {
pub struct RwLockReadGuard<'lock, T: AsFd> {
lock: &'lock RwLock<T>,
}

impl<'lock, T: AsRawFd> RwLockReadGuard<'lock, T> {
impl<'lock, T: AsFd> RwLockReadGuard<'lock, T> {
pub(crate) fn new(lock: &'lock RwLock<T>) -> Self {
Self { lock }
}
}

impl<T: AsRawFd> ops::Deref for RwLockReadGuard<'_, T> {
impl<T: AsFd> ops::Deref for RwLockReadGuard<'_, T> {
type Target = T;

#[inline]
Expand All @@ -24,7 +24,7 @@ impl<T: AsRawFd> ops::Deref for RwLockReadGuard<'_, T> {
}
}

impl<T: AsRawFd> Drop for RwLockReadGuard<'_, T> {
impl<T: AsFd> Drop for RwLockReadGuard<'_, T> {
#[inline]
fn drop(&mut self) {
let _ = flock(&self.lock.as_fd(), FlockOperation::Unlock).ok();
Expand Down
17 changes: 3 additions & 14 deletions src/sys/unix/rw_lock.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
use rustix::fd::BorrowedFd;
use rustix::fd::AsFd;
use rustix::fs::{flock, FlockOperation};
use std::io::{self, Error, ErrorKind};
use std::os::unix::io::AsRawFd;

use super::{RwLockReadGuard, RwLockWriteGuard};

#[derive(Debug)]
pub struct RwLock<T: AsRawFd> {
pub struct RwLock<T: AsFd> {
pub(crate) inner: T,
}

impl<T: AsRawFd> RwLock<T> {
impl<T: AsFd> RwLock<T> {
#[inline]
pub fn new(inner: T) -> Self {
RwLock { inner }
Expand Down Expand Up @@ -57,14 +56,4 @@ impl<T: AsRawFd> RwLock<T> {
{
self.inner
}

#[inline]
pub(crate) fn as_fd(&self) -> BorrowedFd<'_> {
// Safety: We assume that `self.inner`'s file descriptor is valid for
// at least the lifetime of `self`.
//
// Once I/O safety is stablized in std, we can switch the public API to
// use `AsFd` instead of `AsRawFd` and eliminate this `unsafe` block.
unsafe { BorrowedFd::borrow_raw_fd(self.inner.as_raw_fd()) }
}
}
12 changes: 6 additions & 6 deletions src/sys/unix/write_guard.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
use rustix::fd::AsFd;
use rustix::fs::{flock, FlockOperation};
use std::ops;
use std::os::unix::io::AsRawFd;

use super::RwLock;

#[derive(Debug)]
pub struct RwLockWriteGuard<'lock, T: AsRawFd> {
pub struct RwLockWriteGuard<'lock, T: AsFd> {
lock: &'lock mut RwLock<T>,
}

impl<'lock, T: AsRawFd> RwLockWriteGuard<'lock, T> {
impl<'lock, T: AsFd> RwLockWriteGuard<'lock, T> {
pub(crate) fn new(lock: &'lock mut RwLock<T>) -> Self {
Self { lock }
}
}

impl<T: AsRawFd> ops::Deref for RwLockWriteGuard<'_, T> {
impl<T: AsFd> ops::Deref for RwLockWriteGuard<'_, T> {
type Target = T;

#[inline]
Expand All @@ -24,14 +24,14 @@ impl<T: AsRawFd> ops::Deref for RwLockWriteGuard<'_, T> {
}
}

impl<T: AsRawFd> ops::DerefMut for RwLockWriteGuard<'_, T> {
impl<T: AsFd> ops::DerefMut for RwLockWriteGuard<'_, T> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.lock.inner
}
}

impl<T: AsRawFd> Drop for RwLockWriteGuard<'_, T> {
impl<T: AsFd> Drop for RwLockWriteGuard<'_, T> {
#[inline]
fn drop(&mut self) {
let _ = flock(&self.lock.as_fd(), FlockOperation::Unlock).ok();
Expand Down
9 changes: 5 additions & 4 deletions src/sys/windows/read_guard.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use io_lifetimes::AsHandle;
use windows_sys::Win32::Storage::FileSystem::UnlockFile;

use std::ops;
Expand All @@ -7,11 +8,11 @@ use super::utils::syscall;
use super::RwLock;

#[derive(Debug)]
pub struct RwLockReadGuard<'lock, T: AsRawHandle> {
pub struct RwLockReadGuard<'lock, T: AsHandle> {
pub(crate) lock: &'lock RwLock<T>,
}

impl<T: AsRawHandle> ops::Deref for RwLockReadGuard<'_, T> {
impl<T: AsHandle> ops::Deref for RwLockReadGuard<'_, T> {
type Target = T;

#[inline]
Expand All @@ -20,10 +21,10 @@ impl<T: AsRawHandle> ops::Deref for RwLockReadGuard<'_, T> {
}
}

impl<T: AsRawHandle> Drop for RwLockReadGuard<'_, T> {
impl<T: AsHandle> Drop for RwLockReadGuard<'_, T> {
#[inline]
fn drop(&mut self) {
let handle = self.lock.inner.as_raw_handle();
let handle = self.lock.inner.as_handle().as_raw_handle();
syscall(unsafe { UnlockFile(handle, 0, 0, 1, 0) })
.expect("Could not unlock the file descriptor");
}
Expand Down
13 changes: 7 additions & 6 deletions src/sys/windows/rw_lock.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use io_lifetimes::AsHandle;
use std::io::{self, Error, ErrorKind};
use std::os::windows::io::AsRawHandle;

Expand All @@ -9,11 +10,11 @@ use super::utils::{syscall, Overlapped};
use super::{RwLockReadGuard, RwLockWriteGuard};

#[derive(Debug)]
pub struct RwLock<T: AsRawHandle> {
pub struct RwLock<T: AsHandle> {
pub(crate) inner: T,
}

impl<T: AsRawHandle> RwLock<T> {
impl<T: AsHandle> RwLock<T> {
#[inline]
pub fn new(inner: T) -> Self {
RwLock { inner }
Expand All @@ -22,7 +23,7 @@ impl<T: AsRawHandle> RwLock<T> {
#[inline]
pub fn read(&self) -> io::Result<RwLockReadGuard<'_, T>> {
// See: https://stackoverflow.com/a/9186532, https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-lockfileex
let handle = self.inner.as_raw_handle();
let handle = self.inner.as_handle().as_raw_handle();
let overlapped = Overlapped::zero();
let flags = 0;
syscall(unsafe { LockFileEx(handle, flags, 0, 1, 0, overlapped.raw()) })?;
Expand All @@ -31,7 +32,7 @@ impl<T: AsRawHandle> RwLock<T> {

#[inline]
pub fn try_read(&self) -> io::Result<RwLockReadGuard<'_, T>> {
let handle = self.inner.as_raw_handle();
let handle = self.inner.as_handle().as_raw_handle();
let overlapped = Overlapped::zero();
let flags = LOCKFILE_FAIL_IMMEDIATELY;

Expand All @@ -43,7 +44,7 @@ impl<T: AsRawHandle> RwLock<T> {
#[inline]
pub fn write(&mut self) -> io::Result<RwLockWriteGuard<'_, T>> {
// See: https://stackoverflow.com/a/9186532, https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-lockfileex
let handle = self.inner.as_raw_handle();
let handle = self.inner.as_handle().as_raw_handle();
let overlapped = Overlapped::zero();
let flags = LOCKFILE_EXCLUSIVE_LOCK;
syscall(unsafe { LockFileEx(handle, flags, 0, 1, 0, overlapped.raw()) })?;
Expand All @@ -52,7 +53,7 @@ impl<T: AsRawHandle> RwLock<T> {

#[inline]
pub fn try_write(&mut self) -> io::Result<RwLockWriteGuard<'_, T>> {
let handle = self.inner.as_raw_handle();
let handle = self.inner.as_handle().as_raw_handle();
let overlapped = Overlapped::zero();
let flags = LOCKFILE_FAIL_IMMEDIATELY | LOCKFILE_EXCLUSIVE_LOCK;

Expand Down
11 changes: 6 additions & 5 deletions src/sys/windows/write_guard.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use io_lifetimes::AsHandle;
use windows_sys::Win32::Storage::FileSystem::UnlockFile;

use std::ops;
Expand All @@ -7,11 +8,11 @@ use super::utils::syscall;
use super::RwLock;

#[derive(Debug)]
pub struct RwLockWriteGuard<'lock, T: AsRawHandle> {
pub struct RwLockWriteGuard<'lock, T: AsHandle> {
pub(crate) lock: &'lock mut RwLock<T>,
}

impl<T: AsRawHandle> ops::Deref for RwLockWriteGuard<'_, T> {
impl<T: AsHandle> ops::Deref for RwLockWriteGuard<'_, T> {
type Target = T;

#[inline]
Expand All @@ -20,17 +21,17 @@ impl<T: AsRawHandle> ops::Deref for RwLockWriteGuard<'_, T> {
}
}

impl<T: AsRawHandle> ops::DerefMut for RwLockWriteGuard<'_, T> {
impl<T: AsHandle> ops::DerefMut for RwLockWriteGuard<'_, T> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.lock.inner
}
}

impl<T: AsRawHandle> Drop for RwLockWriteGuard<'_, T> {
impl<T: AsHandle> Drop for RwLockWriteGuard<'_, T> {
#[inline]
fn drop(&mut self) {
let handle = self.lock.inner.as_raw_handle();
let handle = self.lock.inner.as_handle().as_raw_handle();
syscall(unsafe { UnlockFile(handle, 0, 0, 1, 0) })
.expect("Could not unlock the file descriptor");
}
Expand Down

0 comments on commit 4bb9c47

Please sign in to comment.