Skip to content

Commit 2b79c9b

Browse files
Epoll type
1 parent 1aa9883 commit 2b79c9b

File tree

2 files changed

+114
-72
lines changed

2 files changed

+114
-72
lines changed

src/sys/epoll.rs

+103-60
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 {
@@ -26,6 +25,107 @@ libc_bitflags!(
2625
}
2726
);
2827

28+
/// A safe wrapper around [`epoll`](https://man7.org/linux/man-pages/man7/epoll.7.html).
29+
/// ```
30+
/// # use nix::sys::{epoll::{Epoll, EpollEvent, EpollFlags, EpollCreateFlags}, eventfd::{eventfd, EfdFlags}};
31+
/// # use nix::unistd::write;
32+
/// # use std::os::unix::io::{OwnedFd, FromRawFd, AsRawFd, AsFd};
33+
/// # use std::time::{Instant, Duration};
34+
/// # fn main() -> nix::Result<()> {
35+
/// const DATA: u64 = 17;
36+
/// const MILLIS: u64 = 100;
37+
///
38+
/// // Create epoll
39+
/// let epoll = Epoll::new(EpollCreateFlags::empty())?;
40+
///
41+
/// // Create eventfd & Add event
42+
/// let eventfd = unsafe { OwnedFd::from_raw_fd(eventfd(0, EfdFlags::empty())?) };
43+
/// epoll.add(eventfd.as_fd(), EpollEvent::new(EpollFlags::EPOLLIN,DATA))?;
44+
///
45+
/// // Arm eventfd & Time wait
46+
/// write(eventfd.as_raw_fd(), &1u64.to_ne_bytes())?;
47+
/// let now = Instant::now();
48+
///
49+
/// // Wait on event
50+
/// let mut events = [EpollEvent::empty()];
51+
/// epoll.wait(&mut events, MILLIS as isize);
52+
///
53+
/// // Assert data correct & timeout didn't occur
54+
/// assert_eq!(events[0].data(), DATA);
55+
/// assert!(now.elapsed() < Duration::from_millis(MILLIS));
56+
/// # Ok(())
57+
/// # }
58+
/// ```
59+
#[derive(Debug)]
60+
pub struct Epoll(pub OwnedFd);
61+
impl Epoll {
62+
/// Creates a new epoll instance and returns a file descriptor referring to that instance.
63+
///
64+
/// [`epoll_create1`](https://man7.org/linux/man-pages/man2/epoll_create1.2.html).
65+
pub fn new(flags: EpollCreateFlags) -> Result<Self> {
66+
let res = unsafe { libc::epoll_create1(flags.bits()) };
67+
let fd = Errno::result(res)?;
68+
let owned_fd = unsafe { OwnedFd::from_raw_fd(fd) };
69+
Ok(Self(owned_fd))
70+
}
71+
/// Add an entry to the interest list of the epoll file descriptor for
72+
/// specified in events.
73+
///
74+
/// [`epoll_ctl`](https://man7.org/linux/man-pages/man2/epoll_ctl.2.html) with `EPOLL_CTL_ADD`.
75+
pub fn add<Fd: AsFd>(&self, fd: Fd, mut event: EpollEvent) -> Result<()> {
76+
self.epoll_ctl(EpollOp::EpollCtlAdd,fd.as_fd().as_raw_fd(),&mut event)
77+
}
78+
/// Remove (deregister) the target file descriptor `fd` from the interest list.
79+
///
80+
/// [`epoll_ctl`](https://man7.org/linux/man-pages/man2/epoll_ctl.2.html) with `EPOLL_CTL_DEL` .
81+
pub fn delete<Fd: AsFd>(&self, fd: Fd) -> Result<()> {
82+
self.epoll_ctl(EpollOp::EpollCtlDel,fd.as_fd().as_raw_fd(),None)
83+
}
84+
/// Change the settings associated with `fd` in the interest list to the new settings specified
85+
/// in `event`.
86+
///
87+
/// [`epoll_ctl`](https://man7.org/linux/man-pages/man2/epoll_ctl.2.html) with `EPOLL_CTL_MOD`.
88+
pub fn modify<Fd: AsFd>(&self,fd: Fd, event: &mut EpollEvent) -> Result<()> {
89+
self.epoll_ctl(EpollOp::EpollCtlMod,fd.as_fd().as_raw_fd(),event)
90+
}
91+
/// Waits for I/O events, blocking the calling thread if no events are currently available.
92+
/// (This can be thought of as fetching items from the ready list of the epoll instance.)
93+
///
94+
/// [`epoll_wait`](https://man7.org/linux/man-pages/man2/epoll_wait.2.html)
95+
pub fn wait(&self, events: &mut [EpollEvent], timeout: isize) -> Result<usize> {
96+
let res = unsafe {
97+
libc::epoll_wait(
98+
self.0.as_raw_fd(),
99+
events.as_mut_ptr() as *mut libc::epoll_event,
100+
events.len() as c_int,
101+
timeout as c_int,
102+
)
103+
};
104+
105+
Errno::result(res).map(|r| r as usize)
106+
}
107+
/// This system call is used to add, modify, or remove entries in the interest list of the epoll
108+
/// instance referred to by `self`. It requests that the operation `op` be performed for the
109+
/// target file descriptor, `fd`.
110+
///
111+
/// [`epoll_ctl`](https://man7.org/linux/man-pages/man2/epoll_ctl.2.html)
112+
pub fn epoll_ctl<'a, T>(
113+
&self,
114+
op: EpollOp,
115+
fd: RawFd,
116+
event: T,
117+
) -> Result<()>
118+
where
119+
T: Into<Option<&'a mut EpollEvent>>,
120+
{
121+
let event: Option<&mut EpollEvent> = event.into();
122+
let ptr = event.map(|x|&mut x.event as *mut libc::epoll_event).unwrap_or(std::ptr::null_mut());
123+
unsafe {
124+
Errno::result(libc::epoll_ctl(self.0.as_raw_fd(), op as c_int, fd, ptr)).map(drop)
125+
}
126+
}
127+
}
128+
29129
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
30130
#[repr(i32)]
31131
#[non_exhaustive]
@@ -68,61 +168,4 @@ impl EpollEvent {
68168
pub fn data(&self) -> u64 {
69169
self.event.u64
70170
}
71-
}
72-
73-
#[inline]
74-
pub fn epoll_create() -> Result<RawFd> {
75-
let res = unsafe { libc::epoll_create(1024) };
76-
77-
Errno::result(res)
78-
}
79-
80-
#[inline]
81-
pub fn epoll_create1(flags: EpollCreateFlags) -> Result<RawFd> {
82-
let res = unsafe { libc::epoll_create1(flags.bits()) };
83-
84-
Errno::result(res)
85-
}
86-
87-
#[inline]
88-
pub fn epoll_ctl<'a, T>(
89-
epfd: RawFd,
90-
op: EpollOp,
91-
fd: RawFd,
92-
event: T,
93-
) -> Result<()>
94-
where
95-
T: Into<Option<&'a mut EpollEvent>>,
96-
{
97-
let mut event: Option<&mut EpollEvent> = event.into();
98-
if event.is_none() && op != EpollOp::EpollCtlDel {
99-
Err(Errno::EINVAL)
100-
} else {
101-
let res = unsafe {
102-
if let Some(ref mut event) = event {
103-
libc::epoll_ctl(epfd, op as c_int, fd, &mut event.event)
104-
} else {
105-
libc::epoll_ctl(epfd, op as c_int, fd, ptr::null_mut())
106-
}
107-
};
108-
Errno::result(res).map(drop)
109-
}
110-
}
111-
112-
#[inline]
113-
pub fn epoll_wait(
114-
epfd: RawFd,
115-
events: &mut [EpollEvent],
116-
timeout_ms: isize,
117-
) -> Result<usize> {
118-
let res = unsafe {
119-
libc::epoll_wait(
120-
epfd,
121-
events.as_mut_ptr() as *mut libc::epoll_event,
122-
events.len() as c_int,
123-
timeout_ms as c_int,
124-
)
125-
};
126-
127-
Errno::result(res).map(|r| r as usize)
128-
}
171+
}

test/sys/test_epoll.rs

+11-12
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,23 @@
11
use nix::errno::Errno;
2-
use nix::sys::epoll::{epoll_create1, epoll_ctl};
3-
use nix::sys::epoll::{EpollCreateFlags, EpollEvent, EpollFlags, EpollOp};
2+
use nix::sys::epoll::{
3+
Epoll, EpollCreateFlags, EpollEvent, EpollFlags, EpollOp,
4+
};
45

56
#[test]
67
pub fn test_epoll_errno() {
7-
let efd = epoll_create1(EpollCreateFlags::empty()).unwrap();
8-
let result = epoll_ctl(efd, EpollOp::EpollCtlDel, 1, None);
9-
result.expect_err("assertion failed");
10-
assert_eq!(result.unwrap_err(), Errno::ENOENT);
8+
let efd = Epoll::new(EpollCreateFlags::empty()).unwrap();
9+
let result = efd.epoll_ctl(EpollOp::EpollCtlDel, 1, None);
10+
assert_eq!(result, Err(Errno::ENOENT));
1111

12-
let result = epoll_ctl(efd, EpollOp::EpollCtlAdd, 1, None);
13-
result.expect_err("assertion failed");
14-
assert_eq!(result.unwrap_err(), Errno::EINVAL);
12+
let result = efd.epoll_ctl(EpollOp::EpollCtlAdd, 1, None);
13+
assert_eq!(result, Err(Errno::EFAULT));
1514
}
1615

1716
#[test]
1817
pub fn test_epoll_ctl() {
19-
let efd = epoll_create1(EpollCreateFlags::empty()).unwrap();
18+
let efd = Epoll::new(EpollCreateFlags::empty()).unwrap();
2019
let mut event =
2120
EpollEvent::new(EpollFlags::EPOLLIN | EpollFlags::EPOLLERR, 1);
22-
epoll_ctl(efd, EpollOp::EpollCtlAdd, 1, &mut event).unwrap();
23-
epoll_ctl(efd, EpollOp::EpollCtlDel, 1, None).unwrap();
21+
efd.epoll_ctl(EpollOp::EpollCtlAdd, 1, &mut event).unwrap();
22+
efd.epoll_ctl(EpollOp::EpollCtlDel, 1, None).unwrap();
2423
}

0 commit comments

Comments
 (0)