Skip to content

Commit b936348

Browse files
Epoll type
1 parent e54498c commit b936348

File tree

3 files changed

+139
-7
lines changed

3 files changed

+139
-7
lines changed

CHANGELOG.md

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

6868
- The MSRV is now 1.63.0
6969
([#1882](https://github.com/nix-rust/nix/pull/1882))
70+
- The epoll interface now uses a type.
71+
([#1882](https://github.com/nix-rust/nix/pull/1882))
7072
- The `addr` argument of `sys::mman::mmap` is now of type `Option<NonZeroUsize>`.
7173
([#1870](https://github.com/nix-rust/nix/pull/1870))
7274
- The `length` argument of `sys::mman::mmap` is now of type `NonZeroUsize`.

src/sys/epoll.rs

+110-4
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,20 +69,126 @@ 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, 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,&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,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,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+
/// When possible prefer [`Epoll::add`], [`Epoll::delete`] and [`Epoll::modify`].
156+
///
157+
/// [`epoll_ctl`](https://man7.org/linux/man-pages/man2/epoll_ctl.2.html)
158+
fn epoll_ctl<'a, Fd: AsFd, T>(
159+
&self,
160+
op: EpollOp,
161+
fd: Fd,
162+
event: T,
163+
) -> Result<()>
164+
where
165+
T: Into<Option<&'a mut EpollEvent>>,
166+
{
167+
let event: Option<&mut EpollEvent> = event.into();
168+
let ptr = event.map(|x|&mut x.event as *mut libc::epoll_event).unwrap_or(std::ptr::null_mut());
169+
unsafe {
170+
Errno::result(libc::epoll_ctl(self.0.as_raw_fd(), op as c_int, fd.as_fd().as_raw_fd(), ptr)).map(drop)
171+
}
172+
}
173+
}
174+
175+
#[deprecated(since = "0.27.0", note = "Use Epoll::new() instead")]
73176
#[inline]
74177
pub fn epoll_create() -> Result<RawFd> {
75178
let res = unsafe { libc::epoll_create(1024) };
76179

77180
Errno::result(res)
78181
}
79182

183+
#[deprecated(since = "0.27.0", note = "Use Epoll::new() instead")]
80184
#[inline]
81185
pub fn epoll_create1(flags: EpollCreateFlags) -> Result<RawFd> {
82186
let res = unsafe { libc::epoll_create1(flags.bits()) };
83187

84188
Errno::result(res)
85189
}
86190

191+
#[deprecated(since = "0.27.0", note = "Use Epoll::epoll_ctl() instead")]
87192
#[inline]
88193
pub fn epoll_ctl<'a, T>(
89194
epfd: RawFd,
@@ -102,13 +207,14 @@ where
102207
if let Some(ref mut event) = event {
103208
libc::epoll_ctl(epfd, op as c_int, fd, &mut event.event)
104209
} else {
105-
libc::epoll_ctl(epfd, op as c_int, fd, ptr::null_mut())
210+
libc::epoll_ctl(epfd, op as c_int, fd, std::ptr::null_mut())
106211
}
107212
};
108213
Errno::result(res).map(drop)
109214
}
110215
}
111216

217+
#[deprecated(since = "0.27.0", note = "Use Epoll::wait() instead")]
112218
#[inline]
113219
pub fn epoll_wait(
114220
epfd: RawFd,
@@ -125,4 +231,4 @@ pub fn epoll_wait(
125231
};
126232

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

test/sys/test_epoll.rs

+27-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
1+
#![allow(deprecated)]
2+
3+
use std::os::unix::io::{OwnedFd,FromRawFd};
4+
15
use nix::errno::Errno;
26
use nix::sys::epoll::{epoll_create1, epoll_ctl};
3-
use nix::sys::epoll::{EpollCreateFlags, EpollEvent, EpollFlags, EpollOp};
7+
use nix::sys::epoll::{
8+
Epoll, EpollCreateFlags, EpollEvent, EpollFlags, EpollOp,
9+
};
410

511
#[test]
6-
pub fn test_epoll_errno() {
12+
pub fn test_deprecated_epoll_errno() {
713
let efd = epoll_create1(EpollCreateFlags::empty()).unwrap();
814
let result = epoll_ctl(efd, EpollOp::EpollCtlDel, 1, None);
915
result.expect_err("assertion failed");
@@ -15,10 +21,28 @@ pub fn test_epoll_errno() {
1521
}
1622

1723
#[test]
18-
pub fn test_epoll_ctl() {
24+
pub fn test_deprecated_epoll_ctl() {
1925
let efd = epoll_create1(EpollCreateFlags::empty()).unwrap();
2026
let mut event =
2127
EpollEvent::new(EpollFlags::EPOLLIN | EpollFlags::EPOLLERR, 1);
2228
epoll_ctl(efd, EpollOp::EpollCtlAdd, 1, &mut event).unwrap();
2329
epoll_ctl(efd, EpollOp::EpollCtlDel, 1, None).unwrap();
2430
}
31+
32+
#[test]
33+
pub fn test_epoll_errno() {
34+
let efd = Epoll::new(EpollCreateFlags::empty()).unwrap();
35+
let fd = unsafe { OwnedFd::from_raw_fd(1) };
36+
let result = efd.delete(&fd);
37+
assert_eq!(result, Err(Errno::ENOENT));
38+
}
39+
40+
#[test]
41+
pub fn test_epoll_ctl() {
42+
let efd = Epoll::new(EpollCreateFlags::empty()).unwrap();
43+
let fd = unsafe { OwnedFd::from_raw_fd(1) };
44+
let event =
45+
EpollEvent::new(EpollFlags::EPOLLIN | EpollFlags::EPOLLERR, 1);
46+
efd.add(&fd, event).unwrap();
47+
efd.delete(&fd).unwrap();
48+
}

0 commit comments

Comments
 (0)