Skip to content

Commit

Permalink
Implement I/O safety traits (#134)
Browse files Browse the repository at this point in the history
* fix unneeded try_into

* use OwnedFd polyfill

* fmt
  • Loading branch information
notgull authored Aug 24, 2022
1 parent 2e7b6fd commit 776c68c
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 50 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ members = [ "io-uring-test", "io-uring-bench" ]
unstable = []
overwrite = [ "bindgen" ]
direct-syscall = [ "sc" ]
io_safety = []

[dependencies]
bitflags = "1"
Expand Down
30 changes: 21 additions & 9 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,24 @@ mod submit;
mod sys;
pub mod types;

use std::convert::TryInto;
use std::mem::ManuallyDrop;
use std::os::unix::io::{AsRawFd, RawFd};
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
use std::{cmp, io, mem};

#[cfg(feature = "io_safety")]
use std::os::unix::io::{AsFd, BorrowedFd};

pub use cqueue::CompletionQueue;
pub use register::Probe;
pub use squeue::SubmissionQueue;
pub use submit::Submitter;
use util::{Fd, Mmap};
use util::{Mmap, OwnedFd};

/// IoUring instance
pub struct IoUring {
sq: squeue::Inner,
cq: cqueue::Inner,
fd: Fd,
fd: OwnedFd,
params: Parameters,
memory: ManuallyDrop<MemoryMap>,
}
Expand Down Expand Up @@ -83,7 +85,7 @@ impl IoUring {
// I really hope that Rust can safely use self-reference types.
#[inline]
unsafe fn setup_queue(
fd: &Fd,
fd: &OwnedFd,
p: &sys::io_uring_params,
) -> io::Result<(MemoryMap, squeue::Inner, cqueue::Inner)> {
let sq_len = p.sq_off.array as usize + p.sq_entries as usize * mem::size_of::<u32>();
Expand Down Expand Up @@ -121,10 +123,13 @@ impl IoUring {
}
}

let fd: Fd = unsafe {
sys::io_uring_setup(entries, &mut p)
.try_into()
.map_err(|_| io::Error::last_os_error())?
let fd: OwnedFd = unsafe {
let fd = sys::io_uring_setup(entries, &mut p);
if fd >= 0 {
OwnedFd::from_raw_fd(fd)
} else {
return Err(io::Error::last_os_error());
}
};

let (mm, sq, cq) = unsafe { setup_queue(&fd, &p)? };
Expand Down Expand Up @@ -451,3 +456,10 @@ impl AsRawFd for IoUring {
self.fd.as_raw_fd()
}
}

#[cfg(feature = "io_safety")]
impl AsFd for IoUring {
fn as_fd(&self) -> BorrowedFd<'_> {
self.fd.as_fd()
}
}
6 changes: 3 additions & 3 deletions src/submit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::{io, ptr};

use crate::register::{execute, Probe};
use crate::sys;
use crate::util::{cast_ptr, Fd};
use crate::util::{cast_ptr, OwnedFd};
use crate::Parameters;

#[cfg(feature = "unstable")]
Expand All @@ -19,7 +19,7 @@ use crate::types;
/// io_uring supports both directly performing I/O on buffers and file descriptors and registering
/// them beforehand. Registering is slow, but it makes performing the actual I/O much faster.
pub struct Submitter<'a> {
fd: &'a Fd,
fd: &'a OwnedFd,
params: &'a Parameters,

sq_head: *const atomic::AtomicU32,
Expand All @@ -30,7 +30,7 @@ pub struct Submitter<'a> {
impl<'a> Submitter<'a> {
#[inline]
pub(crate) const fn new(
fd: &'a Fd,
fd: &'a OwnedFd,
params: &'a Parameters,
sq_head: *const atomic::AtomicU32,
sq_tail: *const atomic::AtomicU32,
Expand Down
75 changes: 37 additions & 38 deletions src/util.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use std::convert::TryFrom;
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use std::os::unix::io::AsRawFd;
use std::sync::atomic;
use std::{io, mem, ptr};
use std::{io, ptr};

/// A region of memory mapped using `mmap(2)`.
pub struct Mmap {
Expand All @@ -11,7 +10,7 @@ pub struct Mmap {

impl Mmap {
/// Map `len` bytes starting from the offset `offset` in the file descriptor `fd` into memory.
pub fn new(fd: &Fd, offset: libc::off_t, len: usize) -> io::Result<Mmap> {
pub fn new(fd: &OwnedFd, offset: libc::off_t, len: usize) -> io::Result<Mmap> {
unsafe {
match libc::mmap(
ptr::null_mut(),
Expand Down Expand Up @@ -60,49 +59,49 @@ impl Drop for Mmap {
}
}

/// An owned file descriptor.
pub struct Fd(pub RawFd);
pub use fd::OwnedFd;

impl TryFrom<RawFd> for Fd {
type Error = ();

#[inline]
fn try_from(value: RawFd) -> Result<Fd, Self::Error> {
if value >= 0 {
Ok(Fd(value))
} else {
Err(())
}
}
#[cfg(feature = "io_safety")]
mod fd {
pub use std::os::unix::io::OwnedFd;
}

impl AsRawFd for Fd {
#[inline]
fn as_raw_fd(&self) -> RawFd {
self.0
#[cfg(not(feature = "io_safety"))]
mod fd {
use std::mem;
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};

/// API-compatible with the `OwnedFd` type in the Rust stdlib.
pub struct OwnedFd(RawFd);

impl AsRawFd for OwnedFd {
#[inline]
fn as_raw_fd(&self) -> RawFd {
self.0
}
}
}

impl IntoRawFd for Fd {
#[inline]
fn into_raw_fd(self) -> RawFd {
let fd = self.0;
mem::forget(self);
fd
impl IntoRawFd for OwnedFd {
#[inline]
fn into_raw_fd(self) -> RawFd {
let fd = self.0;
mem::forget(self);
fd
}
}
}

impl FromRawFd for Fd {
#[inline]
unsafe fn from_raw_fd(fd: RawFd) -> Fd {
Fd(fd)
impl FromRawFd for OwnedFd {
#[inline]
unsafe fn from_raw_fd(fd: RawFd) -> OwnedFd {
OwnedFd(fd)
}
}
}

impl Drop for Fd {
fn drop(&mut self) {
unsafe {
libc::close(self.0);
impl Drop for OwnedFd {
fn drop(&mut self) {
unsafe {
libc::close(self.0);
}
}
}
}
Expand Down

0 comments on commit 776c68c

Please sign in to comment.