diff options
-rw-r--r-- | .cirrus.yml | 2 | ||||
-rw-r--r-- | CHANGELOG.md | 2 | ||||
-rw-r--r-- | src/sys/epoll.rs | 114 | ||||
-rw-r--r-- | src/sys/statfs.rs | 6 | ||||
-rw-r--r-- | test/sys/test_epoll.rs | 2 | ||||
-rw-r--r-- | test/test_fcntl.rs | 4 |
6 files changed, 120 insertions, 10 deletions
diff --git a/.cirrus.yml b/.cirrus.yml index d69716db..21369672 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -42,7 +42,7 @@ task: matrix: - name: FreeBSD 12 amd64 & i686 freebsd_instance: - image: freebsd-12-3-release-amd64 + image: freebsd-12-4-release-amd64 - name: FreeBSD 14 amd64 & i686 freebsd_instance: image_family: freebsd-14-0-snap diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f7855d3..f6ee0fc5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). - The MSRV is now 1.63 ([#1862](https://github.com/nix-rust/nix/pull/1862)) +- The epoll interface now uses a type. + ([#1882](https://github.com/nix-rust/nix/pull/1882)) ### Fixed ### Removed diff --git a/src/sys/epoll.rs b/src/sys/epoll.rs index 58def2e7..02c25d4d 100644 --- a/src/sys/epoll.rs +++ b/src/sys/epoll.rs @@ -2,8 +2,7 @@ use crate::errno::Errno; use crate::Result; use libc::{self, c_int}; use std::mem; -use std::os::unix::io::RawFd; -use std::ptr; +use std::os::unix::io::{FromRawFd,RawFd, OwnedFd, AsFd, AsRawFd}; libc_bitflags!( pub struct EpollFlags: c_int { @@ -70,6 +69,110 @@ impl EpollEvent { } } +/// A safe wrapper around [`epoll`](https://man7.org/linux/man-pages/man7/epoll.7.html). +/// ``` +/// # use nix::sys::{epoll::{Epoll, EpollEvent, EpollFlags, EpollCreateFlags}, eventfd::{eventfd, EfdFlags}}; +/// # use nix::unistd::write; +/// # use std::os::unix::io::{OwnedFd, FromRawFd, AsRawFd, AsFd}; +/// # use std::time::{Instant, Duration}; +/// # 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())?) }; +/// 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)); +/// # Ok(()) +/// # } +/// ``` +#[derive(Debug)] +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()) }; + let fd = Errno::result(res)?; + let owned_fd = unsafe { OwnedFd::from_raw_fd(fd) }; + Ok(Self(owned_fd)) + } + /// Add an entry to the interest list of the epoll file descriptor for + /// 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) + } + /// 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) + } + /// 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) + } + /// 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> { + let res = unsafe { + libc::epoll_wait( + self.0.as_raw_fd(), + events.as_mut_ptr() as *mut libc::epoll_event, + events.len() as c_int, + 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, + op: EpollOp, + fd: Fd, + event: T, + ) -> Result<()> + where + 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()); + unsafe { + Errno::result(libc::epoll_ctl(self.0.as_raw_fd(), op as c_int, fd.as_fd().as_raw_fd(), ptr)).map(drop) + } + } +} + +#[deprecated(since = "0.27.0", note = "Use Epoll::new() instead")] #[inline] pub fn epoll_create() -> Result<RawFd> { let res = unsafe { libc::epoll_create(1024) }; @@ -77,6 +180,7 @@ pub fn epoll_create() -> Result<RawFd> { Errno::result(res) } +#[deprecated(since = "0.27.0", note = "Use Epoll::new() instead")] #[inline] pub fn epoll_create1(flags: EpollCreateFlags) -> Result<RawFd> { let res = unsafe { libc::epoll_create1(flags.bits()) }; @@ -84,6 +188,7 @@ pub fn epoll_create1(flags: EpollCreateFlags) -> Result<RawFd> { Errno::result(res) } +#[deprecated(since = "0.27.0", note = "Use Epoll::epoll_ctl() instead")] #[inline] pub fn epoll_ctl<'a, T>( epfd: RawFd, @@ -102,13 +207,14 @@ where if let Some(ref mut event) = event { libc::epoll_ctl(epfd, op as c_int, fd, &mut event.event) } else { - libc::epoll_ctl(epfd, op as c_int, fd, ptr::null_mut()) + libc::epoll_ctl(epfd, op as c_int, fd, std::ptr::null_mut()) } }; Errno::result(res).map(drop) } } +#[deprecated(since = "0.27.0", note = "Use Epoll::wait() instead")] #[inline] pub fn epoll_wait( epfd: RawFd, @@ -125,4 +231,4 @@ pub fn epoll_wait( }; Errno::result(res).map(|r| r as usize) -} +}
\ No newline at end of file diff --git a/src/sys/statfs.rs b/src/sys/statfs.rs index 9be8ca66..721d45cb 100644 --- a/src/sys/statfs.rs +++ b/src/sys/statfs.rs @@ -5,7 +5,7 @@ use std::ffi::CStr; use std::fmt::{self, Debug}; use std::mem; -use std::os::unix::io::AsRawFd; +use std::os::unix::io::{AsFd, AsRawFd}; use cfg_if::cfg_if; @@ -740,10 +740,10 @@ pub fn statfs<P: ?Sized + NixPath>(path: &P) -> Result<Statfs> { /// # Arguments /// /// `fd` - File descriptor of any open file within the file system to describe -pub fn fstatfs<T: AsRawFd>(fd: &T) -> Result<Statfs> { +pub fn fstatfs<Fd: AsFd>(fd: &Fd) -> Result<Statfs> { unsafe { let mut stat = mem::MaybeUninit::<type_of_statfs>::uninit(); - Errno::result(LIBC_FSTATFS(fd.as_raw_fd(), stat.as_mut_ptr())) + Errno::result(LIBC_FSTATFS(fd.as_fd().as_raw_fd(), stat.as_mut_ptr())) .map(|_| Statfs(stat.assume_init())) } } diff --git a/test/sys/test_epoll.rs b/test/sys/test_epoll.rs index 91569159..84b100c1 100644 --- a/test/sys/test_epoll.rs +++ b/test/sys/test_epoll.rs @@ -1,3 +1,5 @@ +#![allow(deprecated)] + use nix::errno::Errno; use nix::sys::epoll::{epoll_create1, epoll_ctl}; use nix::sys::epoll::{EpollCreateFlags, EpollEvent, EpollFlags, EpollOp}; diff --git a/test/test_fcntl.rs b/test/test_fcntl.rs index fb2a5e2e..8f50f16b 100644 --- a/test/test_fcntl.rs +++ b/test/test_fcntl.rs @@ -383,7 +383,7 @@ mod linux_android { let tmp = NamedTempFile::new().unwrap(); let fd = tmp.as_raw_fd(); - let statfs = nix::sys::statfs::fstatfs(&tmp).unwrap(); + let statfs = nix::sys::statfs::fstatfs(tmp.as_file()).unwrap(); if statfs.filesystem_type() == nix::sys::statfs::OVERLAYFS_SUPER_MAGIC { // OverlayFS is a union file system. It returns one inode value in // stat(2), but a different one shows up in /proc/locks. So we must @@ -421,7 +421,7 @@ mod linux_android { let tmp = NamedTempFile::new().unwrap(); let fd = tmp.as_raw_fd(); - let statfs = nix::sys::statfs::fstatfs(&tmp).unwrap(); + let statfs = nix::sys::statfs::fstatfs(tmp.as_file()).unwrap(); if statfs.filesystem_type() == nix::sys::statfs::OVERLAYFS_SUPER_MAGIC { // OverlayFS is a union file system. It returns one inode value in // stat(2), but a different one shows up in /proc/locks. So we must |