Skip to content

Commit

Permalink
feat: I/O safety for 'sys/memfd' & 'sys/event' & 'sys/eventfd'
Browse files Browse the repository at this point in the history
  • Loading branch information
SteveLauC committed Dec 9, 2022
1 parent 7f18847 commit 8f93634
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 38 deletions.
64 changes: 40 additions & 24 deletions src/sys/epoll.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::errno::Errno;
use crate::Result;
use libc::{self, c_int};
use std::mem;
use std::os::unix::io::{FromRawFd,RawFd, OwnedFd, AsFd, AsRawFd};
use std::os::unix::io::{AsFd, AsRawFd, FromRawFd, OwnedFd, RawFd};

libc_bitflags!(
pub struct EpollFlags: c_int {
Expand Down Expand Up @@ -78,22 +78,22 @@ impl EpollEvent {
/// # fn main() -> nix::Result<()> {
/// const DATA: u64 = 17;
/// const MILLIS: u64 = 100;
///
///
/// // Create epoll
/// let epoll = Epoll::new(EpollCreateFlags::empty())?;
///
///
/// // Create eventfd & Add event
/// let eventfd = unsafe { OwnedFd::from_raw_fd(eventfd(0, EfdFlags::empty())?) };
/// let eventfd = unsafe { eventfd(0, EfdFlags::empty())? };
/// epoll.add(&eventfd, EpollEvent::new(EpollFlags::EPOLLIN,DATA))?;
///
///
/// // Arm eventfd & Time wait
/// write(eventfd.as_raw_fd(), &1u64.to_ne_bytes())?;
/// let now = Instant::now();
///
///
/// // Wait on event
/// let mut events = [EpollEvent::empty()];
/// epoll.wait(&mut events, MILLIS as isize)?;
///
///
/// // Assert data correct & timeout didn't occur
/// assert_eq!(events[0].data(), DATA);
/// assert!(now.elapsed() < Duration::from_millis(MILLIS));
Expand All @@ -104,7 +104,7 @@ impl EpollEvent {
pub struct Epoll(pub OwnedFd);
impl Epoll {
/// Creates a new epoll instance and returns a file descriptor referring to that instance.
///
///
/// [`epoll_create1`](https://man7.org/linux/man-pages/man2/epoll_create1.2.html).
pub fn new(flags: EpollCreateFlags) -> Result<Self> {
let res = unsafe { libc::epoll_create1(flags.bits()) };
Expand All @@ -113,30 +113,38 @@ impl Epoll {
Ok(Self(owned_fd))
}
/// Add an entry to the interest list of the epoll file descriptor for
/// specified in events.
///
/// specified in events.
///
/// [`epoll_ctl`](https://man7.org/linux/man-pages/man2/epoll_ctl.2.html) with `EPOLL_CTL_ADD`.
pub fn add<Fd: AsFd>(&self, fd: Fd, mut event: EpollEvent) -> Result<()> {
self.epoll_ctl(EpollOp::EpollCtlAdd,fd,&mut event)
self.epoll_ctl(EpollOp::EpollCtlAdd, fd, &mut event)
}
/// Remove (deregister) the target file descriptor `fd` from the interest list.
///
///
/// [`epoll_ctl`](https://man7.org/linux/man-pages/man2/epoll_ctl.2.html) with `EPOLL_CTL_DEL` .
pub fn delete<Fd: AsFd>(&self, fd: Fd) -> Result<()> {
self.epoll_ctl(EpollOp::EpollCtlDel,fd,None)
self.epoll_ctl(EpollOp::EpollCtlDel, fd, None)
}
/// Change the settings associated with `fd` in the interest list to the new settings specified
/// in `event`.
///
///
/// [`epoll_ctl`](https://man7.org/linux/man-pages/man2/epoll_ctl.2.html) with `EPOLL_CTL_MOD`.
pub fn modify<Fd: AsFd>(&self,fd: Fd, event: &mut EpollEvent) -> Result<()> {
self.epoll_ctl(EpollOp::EpollCtlMod,fd,event)
pub fn modify<Fd: AsFd>(
&self,
fd: Fd,
event: &mut EpollEvent,
) -> Result<()> {
self.epoll_ctl(EpollOp::EpollCtlMod, fd, event)
}
/// Waits for I/O events, blocking the calling thread if no events are currently available.
/// (This can be thought of as fetching items from the ready list of the epoll instance.)
///
///
/// [`epoll_wait`](https://man7.org/linux/man-pages/man2/epoll_wait.2.html)
pub fn wait(&self, events: &mut [EpollEvent], timeout: isize) -> Result<usize> {
pub fn wait(
&self,
events: &mut [EpollEvent],
timeout: isize,
) -> Result<usize> {
let res = unsafe {
libc::epoll_wait(
self.0.as_raw_fd(),
Expand All @@ -145,15 +153,15 @@ impl Epoll {
timeout as c_int,
)
};

Errno::result(res).map(|r| r as usize)
}
/// This system call is used to add, modify, or remove entries in the interest list of the epoll
/// instance referred to by `self`. It requests that the operation `op` be performed for the
/// target file descriptor, `fd`.
///
///
/// When possible prefer [`Epoll::add`], [`Epoll::delete`] and [`Epoll::modify`].
///
///
/// [`epoll_ctl`](https://man7.org/linux/man-pages/man2/epoll_ctl.2.html)
fn epoll_ctl<'a, Fd: AsFd, T>(
&self,
Expand All @@ -165,9 +173,17 @@ impl Epoll {
T: Into<Option<&'a mut EpollEvent>>,
{
let event: Option<&mut EpollEvent> = event.into();
let ptr = event.map(|x|&mut x.event as *mut libc::epoll_event).unwrap_or(std::ptr::null_mut());
let ptr = event
.map(|x| &mut x.event as *mut libc::epoll_event)
.unwrap_or(std::ptr::null_mut());
unsafe {
Errno::result(libc::epoll_ctl(self.0.as_raw_fd(), op as c_int, fd.as_fd().as_raw_fd(), ptr)).map(drop)
Errno::result(libc::epoll_ctl(
self.0.as_raw_fd(),
op as c_int,
fd.as_fd().as_raw_fd(),
ptr,
))
.map(drop)
}
}
}
Expand Down Expand Up @@ -231,4 +247,4 @@ pub fn epoll_wait(
};

Errno::result(res).map(|r| r as usize)
}
}
16 changes: 8 additions & 8 deletions src/sys/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use libc::{c_int, c_long, intptr_t, time_t, timespec, uintptr_t};
use libc::{c_long, intptr_t, size_t, time_t, timespec, uintptr_t};
use std::convert::TryInto;
use std::mem;
use std::os::unix::io::RawFd;
use std::os::unix::io::{AsFd, AsRawFd, FromRawFd, OwnedFd};
use std::ptr;

// Redefine kevent in terms of programmer-friendly enums and bitfields.
Expand Down Expand Up @@ -207,10 +207,10 @@ libc_bitflags!(
}
);

pub fn kqueue() -> Result<RawFd> {
pub fn kqueue() -> Result<OwnedFd> {
let res = unsafe { libc::kqueue() };

Errno::result(res)
Errno::result(res).map(|fd| unsafe { OwnedFd::from_raw_fd(fd) })
}

// KEvent can't derive Send because on some operating systems, udata is defined
Expand Down Expand Up @@ -267,8 +267,8 @@ impl KEvent {
}
}

pub fn kevent(
kq: RawFd,
pub fn kevent<Fd: AsFd>(
kq: Fd,
changelist: &[KEvent],
eventlist: &mut [KEvent],
timeout_ms: usize,
Expand All @@ -293,15 +293,15 @@ type type_of_nchanges = c_int;
#[cfg(target_os = "netbsd")]
type type_of_nchanges = size_t;

pub fn kevent_ts(
kq: RawFd,
pub fn kevent_ts<Fd: AsFd>(
kq: Fd,
changelist: &[KEvent],
eventlist: &mut [KEvent],
timeout_opt: Option<timespec>,
) -> Result<usize> {
let res = unsafe {
libc::kevent(
kq,
kq.as_fd().as_raw_fd(),
changelist.as_ptr() as *const libc::kevent,
changelist.len() as type_of_nchanges,
eventlist.as_mut_ptr() as *mut libc::kevent,
Expand Down
6 changes: 3 additions & 3 deletions src/sys/eventfd.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::errno::Errno;
use crate::Result;
use std::os::unix::io::RawFd;
use std::os::unix::io::{FromRawFd, OwnedFd};

libc_bitflags! {
pub struct EfdFlags: libc::c_int {
Expand All @@ -10,8 +10,8 @@ libc_bitflags! {
}
}

pub fn eventfd(initval: libc::c_uint, flags: EfdFlags) -> Result<RawFd> {
pub fn eventfd(initval: libc::c_uint, flags: EfdFlags) -> Result<OwnedFd> {
let res = unsafe { libc::eventfd(initval, flags.bits()) };

Errno::result(res).map(|r| r as RawFd)
Errno::result(res).map(|r| unsafe { OwnedFd::from_raw_fd(r) })
}
6 changes: 3 additions & 3 deletions src/sys/memfd.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Interfaces for managing memory-backed files.
use cfg_if::cfg_if;
use std::os::unix::io::RawFd;
use std::os::unix::io::{FromRawFd, OwnedFd, RawFd};

use crate::errno::Errno;
use crate::Result;
Expand Down Expand Up @@ -40,7 +40,7 @@ libc_bitflags!(
/// For more information, see [`memfd_create(2)`].
///
/// [`memfd_create(2)`]: https://man7.org/linux/man-pages/man2/memfd_create.2.html
pub fn memfd_create(name: &CStr, flags: MemFdCreateFlag) -> Result<RawFd> {
pub fn memfd_create(name: &CStr, flags: MemFdCreateFlag) -> Result<OwnedFd> {
let res = unsafe {
cfg_if! {
if #[cfg(all(
Expand All @@ -60,5 +60,5 @@ pub fn memfd_create(name: &CStr, flags: MemFdCreateFlag) -> Result<RawFd> {
}
};

Errno::result(res).map(|r| r as RawFd)
Errno::result(res).map(|r| unsafe { OwnedFd::from_raw_fd(r as RawFd) })
}

0 comments on commit 8f93634

Please sign in to comment.