Skip to content

Commit 671338e

Browse files
Epoll type
1 parent 1aa9883 commit 671338e

File tree

3 files changed

+130
-6
lines changed

3 files changed

+130
-6
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ This project adheres to [Semantic Versioning](https://semver.org/).
4343

4444
### Changed
4545

46+
- The epoll interface now uses a type.
47+
([#1882](https://github.com/nix-rust/nix/pull/1882))
4648
- The MSRV is now 1.63.0
4749
([#1882](https://github.com/nix-rust/nix/pull/1882))
4850
- The `addr` argument of `sys::mman::mmap` is now of type `Option<NonZeroUsize>`.

src/sys/epoll.rs

+103-3
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@ use crate::errno::Errno;
22
use crate::Result;
33
use libc::{self, c_int};
44
use std::mem;
5-
use std::os::unix::io::RawFd;
6-
use std::ptr;
5+
use std::os::unix::io::{FromRawFd,RawFd, OwnedFd, AsFd, AsRawFd};
76

87
libc_bitflags!(
98
pub struct EpollFlags: c_int {
@@ -70,6 +69,107 @@ impl EpollEvent {
7069
}
7170
}
7271

72+
/// A safe wrapper around [`epoll`](https://man7.org/linux/man-pages/man7/epoll.7.html).
73+
/// ```
74+
/// # use nix::sys::{epoll::{Epoll, EpollEvent, EpollFlags, EpollCreateFlags}, eventfd::{eventfd, EfdFlags}};
75+
/// # use nix::unistd::write;
76+
/// # use std::os::unix::io::{OwnedFd, FromRawFd, AsRawFd, AsFd};
77+
/// # use std::time::{Instant, Duration};
78+
/// # fn main() -> nix::Result<()> {
79+
/// const DATA: u64 = 17;
80+
/// const MILLIS: u64 = 100;
81+
///
82+
/// // Create epoll
83+
/// let epoll = Epoll::new(EpollCreateFlags::empty())?;
84+
///
85+
/// // Create eventfd & Add event
86+
/// let eventfd = unsafe { OwnedFd::from_raw_fd(eventfd(0, EfdFlags::empty())?) };
87+
/// epoll.add(eventfd.as_fd(), EpollEvent::new(EpollFlags::EPOLLIN,DATA))?;
88+
///
89+
/// // Arm eventfd & Time wait
90+
/// write(eventfd.as_raw_fd(), &1u64.to_ne_bytes())?;
91+
/// let now = Instant::now();
92+
///
93+
/// // Wait on event
94+
/// let mut events = [EpollEvent::empty()];
95+
/// epoll.wait(&mut events, MILLIS as isize);
96+
///
97+
/// // Assert data correct & timeout didn't occur
98+
/// assert_eq!(events[0].data(), DATA);
99+
/// assert!(now.elapsed() < Duration::from_millis(MILLIS));
100+
/// # Ok(())
101+
/// # }
102+
/// ```
103+
#[derive(Debug)]
104+
pub struct Epoll(pub OwnedFd);
105+
impl Epoll {
106+
/// Creates a new epoll instance and returns a file descriptor referring to that instance.
107+
///
108+
/// [`epoll_create1`](https://man7.org/linux/man-pages/man2/epoll_create1.2.html).
109+
pub fn new(flags: EpollCreateFlags) -> Result<Self> {
110+
let res = unsafe { libc::epoll_create1(flags.bits()) };
111+
let fd = Errno::result(res)?;
112+
let owned_fd = unsafe { OwnedFd::from_raw_fd(fd) };
113+
Ok(Self(owned_fd))
114+
}
115+
/// Add an entry to the interest list of the epoll file descriptor for
116+
/// specified in events.
117+
///
118+
/// [`epoll_ctl`](https://man7.org/linux/man-pages/man2/epoll_ctl.2.html) with `EPOLL_CTL_ADD`.
119+
pub fn add<Fd: AsFd>(&self, fd: Fd, mut event: EpollEvent) -> Result<()> {
120+
self.epoll_ctl(EpollOp::EpollCtlAdd,fd.as_fd().as_raw_fd(),&mut event)
121+
}
122+
/// Remove (deregister) the target file descriptor `fd` from the interest list.
123+
///
124+
/// [`epoll_ctl`](https://man7.org/linux/man-pages/man2/epoll_ctl.2.html) with `EPOLL_CTL_DEL` .
125+
pub fn delete<Fd: AsFd>(&self, fd: Fd) -> Result<()> {
126+
self.epoll_ctl(EpollOp::EpollCtlDel,fd.as_fd().as_raw_fd(),None)
127+
}
128+
/// Change the settings associated with `fd` in the interest list to the new settings specified
129+
/// in `event`.
130+
///
131+
/// [`epoll_ctl`](https://man7.org/linux/man-pages/man2/epoll_ctl.2.html) with `EPOLL_CTL_MOD`.
132+
pub fn modify<Fd: AsFd>(&self,fd: Fd, event: &mut EpollEvent) -> Result<()> {
133+
self.epoll_ctl(EpollOp::EpollCtlMod,fd.as_fd().as_raw_fd(),event)
134+
}
135+
/// Waits for I/O events, blocking the calling thread if no events are currently available.
136+
/// (This can be thought of as fetching items from the ready list of the epoll instance.)
137+
///
138+
/// [`epoll_wait`](https://man7.org/linux/man-pages/man2/epoll_wait.2.html)
139+
pub fn wait(&self, events: &mut [EpollEvent], timeout: isize) -> Result<usize> {
140+
let res = unsafe {
141+
libc::epoll_wait(
142+
self.0.as_raw_fd(),
143+
events.as_mut_ptr() as *mut libc::epoll_event,
144+
events.len() as c_int,
145+
timeout as c_int,
146+
)
147+
};
148+
149+
Errno::result(res).map(|r| r as usize)
150+
}
151+
/// This system call is used to add, modify, or remove entries in the interest list of the epoll
152+
/// instance referred to by `self`. It requests that the operation `op` be performed for the
153+
/// target file descriptor, `fd`.
154+
///
155+
/// [`epoll_ctl`](https://man7.org/linux/man-pages/man2/epoll_ctl.2.html)
156+
pub fn epoll_ctl<'a, T>(
157+
&self,
158+
op: EpollOp,
159+
fd: RawFd,
160+
event: T,
161+
) -> Result<()>
162+
where
163+
T: Into<Option<&'a mut EpollEvent>>,
164+
{
165+
let event: Option<&mut EpollEvent> = event.into();
166+
let ptr = event.map(|x|&mut x.event as *mut libc::epoll_event).unwrap_or(std::ptr::null_mut());
167+
unsafe {
168+
Errno::result(libc::epoll_ctl(self.0.as_raw_fd(), op as c_int, fd, ptr)).map(drop)
169+
}
170+
}
171+
}
172+
73173
#[inline]
74174
pub fn epoll_create() -> Result<RawFd> {
75175
let res = unsafe { libc::epoll_create(1024) };
@@ -125,4 +225,4 @@ pub fn epoll_wait(
125225
};
126226

127227
Errno::result(res).map(|r| r as usize)
128-
}
228+
}

test/sys/test_epoll.rs

+25-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
use nix::errno::Errno;
22
use nix::sys::epoll::{epoll_create1, epoll_ctl};
3-
use nix::sys::epoll::{EpollCreateFlags, EpollEvent, EpollFlags, EpollOp};
3+
use nix::sys::epoll::{
4+
Epoll, EpollCreateFlags, EpollEvent, EpollFlags, EpollOp,
5+
};
46

57
#[test]
6-
pub fn test_epoll_errno() {
8+
pub fn test_deprecated_epoll_errno() {
79
let efd = epoll_create1(EpollCreateFlags::empty()).unwrap();
810
let result = epoll_ctl(efd, EpollOp::EpollCtlDel, 1, None);
911
result.expect_err("assertion failed");
@@ -15,10 +17,30 @@ pub fn test_epoll_errno() {
1517
}
1618

1719
#[test]
18-
pub fn test_epoll_ctl() {
20+
pub fn test_deprecated_epoll_ctl() {
1921
let efd = epoll_create1(EpollCreateFlags::empty()).unwrap();
2022
let mut event =
2123
EpollEvent::new(EpollFlags::EPOLLIN | EpollFlags::EPOLLERR, 1);
2224
epoll_ctl(efd, EpollOp::EpollCtlAdd, 1, &mut event).unwrap();
2325
epoll_ctl(efd, EpollOp::EpollCtlDel, 1, None).unwrap();
2426
}
27+
28+
29+
#[test]
30+
pub fn test_epoll_errno() {
31+
let efd = Epoll::new(EpollCreateFlags::empty()).unwrap();
32+
let result = efd.epoll_ctl(EpollOp::EpollCtlDel, 1, None);
33+
assert_eq!(result, Err(Errno::ENOENT));
34+
35+
let result = efd.epoll_ctl(EpollOp::EpollCtlAdd, 1, None);
36+
assert_eq!(result, Err(Errno::EFAULT));
37+
}
38+
39+
#[test]
40+
pub fn test_epoll_ctl() {
41+
let efd = Epoll::new(EpollCreateFlags::empty()).unwrap();
42+
let mut event =
43+
EpollEvent::new(EpollFlags::EPOLLIN | EpollFlags::EPOLLERR, 1);
44+
efd.epoll_ctl(EpollOp::EpollCtlAdd, 1, &mut event).unwrap();
45+
efd.epoll_ctl(EpollOp::EpollCtlDel, 1, None).unwrap();
46+
}

0 commit comments

Comments
 (0)