Refactor epoll tests to use errno_result and improve notification checks
This commit is contained in:
parent
078712ba19
commit
ffaf76a7cf
3 changed files with 75 additions and 118 deletions
|
|
@ -7,6 +7,8 @@ use std::thread;
|
|||
|
||||
#[path = "../../utils/libc.rs"]
|
||||
mod libc_utils;
|
||||
use libc_utils::epoll::*;
|
||||
use libc_utils::*;
|
||||
|
||||
// This is a set of testcases for blocking epoll.
|
||||
|
||||
|
|
@ -20,47 +22,22 @@ fn main() {
|
|||
}
|
||||
|
||||
// Using `as` cast since `EPOLLET` wraps around
|
||||
const EPOLL_IN_OUT_ET: u32 = (libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET) as _;
|
||||
|
||||
#[track_caller]
|
||||
fn check_epoll_wait<const N: usize>(
|
||||
epfd: i32,
|
||||
expected_notifications: &[(u32, u64)],
|
||||
timeout: i32,
|
||||
) {
|
||||
let epoll_event = libc::epoll_event { events: 0, u64: 0 };
|
||||
let mut array: [libc::epoll_event; N] = [epoll_event; N];
|
||||
let maxsize = N;
|
||||
let array_ptr = array.as_mut_ptr();
|
||||
let res = unsafe { libc::epoll_wait(epfd, array_ptr, maxsize.try_into().unwrap(), timeout) };
|
||||
if res < 0 {
|
||||
panic!("epoll_wait failed: {}", std::io::Error::last_os_error());
|
||||
}
|
||||
let got_notifications =
|
||||
unsafe { std::slice::from_raw_parts(array_ptr, res.try_into().unwrap()) };
|
||||
let got_notifications = got_notifications.iter().map(|e| (e.events, e.u64)).collect::<Vec<_>>();
|
||||
assert_eq!(got_notifications, expected_notifications, "got wrong notifications");
|
||||
}
|
||||
const EPOLL_IN_OUT_ET: i32 = (libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET) as _;
|
||||
|
||||
// This test allows epoll_wait to block, then unblock without notification.
|
||||
fn test_epoll_block_without_notification() {
|
||||
// Create an epoll instance.
|
||||
let epfd = unsafe { libc::epoll_create1(0) };
|
||||
assert_ne!(epfd, -1);
|
||||
let epfd = errno_result(unsafe { libc::epoll_create1(0) }).unwrap();
|
||||
|
||||
// Create an eventfd instances.
|
||||
let flags = libc::EFD_NONBLOCK | libc::EFD_CLOEXEC;
|
||||
let fd = unsafe { libc::eventfd(0, flags) };
|
||||
let fd = errno_result(unsafe { libc::eventfd(0, flags) }).unwrap();
|
||||
|
||||
// Register eventfd with epoll.
|
||||
let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: fd as u64 };
|
||||
let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fd, &mut ev) };
|
||||
assert_eq!(res, 0);
|
||||
epoll_ctl_add(epfd, fd, EPOLL_IN_OUT_ET).unwrap();
|
||||
|
||||
// epoll_wait to clear notification.
|
||||
let expected_event = u32::try_from(libc::EPOLLOUT).unwrap();
|
||||
let expected_value = fd as u64;
|
||||
check_epoll_wait::<1>(epfd, &[(expected_event, expected_value)], 0);
|
||||
check_epoll_wait::<1>(epfd, &[Ev { events: libc::EPOLLOUT as _, data: fd }], 0);
|
||||
|
||||
// This epoll wait blocks, and timeout without notification.
|
||||
check_epoll_wait::<1>(epfd, &[], 5);
|
||||
|
|
@ -69,102 +46,86 @@ fn test_epoll_block_without_notification() {
|
|||
// This test triggers notification and unblocks the epoll_wait before timeout.
|
||||
fn test_epoll_block_then_unblock() {
|
||||
// Create an epoll instance.
|
||||
let epfd = unsafe { libc::epoll_create1(0) };
|
||||
assert_ne!(epfd, -1);
|
||||
let epfd = errno_result(unsafe { libc::epoll_create1(0) }).unwrap();
|
||||
|
||||
// Create a socketpair instance.
|
||||
let mut fds = [-1, -1];
|
||||
let res = unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) };
|
||||
assert_eq!(res, 0);
|
||||
errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) });
|
||||
|
||||
// Register one side of the socketpair with epoll.
|
||||
let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: fds[0] as u64 };
|
||||
let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fds[0], &mut ev) };
|
||||
assert_eq!(res, 0);
|
||||
epoll_ctl_add(epfd, fds[0], EPOLL_IN_OUT_ET).unwrap();
|
||||
|
||||
// epoll_wait to clear notification.
|
||||
let expected_event = u32::try_from(libc::EPOLLOUT).unwrap();
|
||||
let expected_value = fds[0] as u64;
|
||||
check_epoll_wait::<1>(epfd, &[(expected_event, expected_value)], 0);
|
||||
check_epoll_wait::<1>(epfd, &[Ev { events: libc::EPOLLOUT as _, data: fds[0] }], 0);
|
||||
|
||||
// epoll_wait before triggering notification so it will block then get unblocked before timeout.
|
||||
let expected_event = u32::try_from(libc::EPOLLIN | libc::EPOLLOUT).unwrap();
|
||||
let expected_value = fds[0] as u64;
|
||||
let thread1 = thread::spawn(move || {
|
||||
thread::yield_now();
|
||||
let data = "abcde".as_bytes().as_ptr();
|
||||
let res = unsafe { libc_utils::write_all(fds[1], data as *const libc::c_void, 5) };
|
||||
assert_eq!(res, 5);
|
||||
write_all_from_slice(fds[1], b"abcde").unwrap();
|
||||
});
|
||||
check_epoll_wait::<1>(epfd, &[(expected_event, expected_value)], 10);
|
||||
check_epoll_wait::<1>(
|
||||
epfd,
|
||||
&[Ev { events: (libc::EPOLLIN | libc::EPOLLOUT) as _, data: fds[0] }],
|
||||
10,
|
||||
);
|
||||
thread1.join().unwrap();
|
||||
}
|
||||
|
||||
// This test triggers a notification after epoll_wait times out.
|
||||
fn test_notification_after_timeout() {
|
||||
// Create an epoll instance.
|
||||
let epfd = unsafe { libc::epoll_create1(0) };
|
||||
assert_ne!(epfd, -1);
|
||||
let epfd = errno_result(unsafe { libc::epoll_create1(0) }).unwrap();
|
||||
|
||||
// Create a socketpair instance.
|
||||
let mut fds = [-1, -1];
|
||||
let res = unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) };
|
||||
assert_eq!(res, 0);
|
||||
errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) });
|
||||
|
||||
// Register one side of the socketpair with epoll.
|
||||
let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: fds[0] as u64 };
|
||||
let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fds[0], &mut ev) };
|
||||
assert_eq!(res, 0);
|
||||
epoll_ctl_add(epfd, fds[0], EPOLL_IN_OUT_ET).unwrap();
|
||||
|
||||
// epoll_wait to clear notification.
|
||||
let expected_event = u32::try_from(libc::EPOLLOUT).unwrap();
|
||||
let expected_value = fds[0] as u64;
|
||||
check_epoll_wait::<1>(epfd, &[(expected_event, expected_value)], 0);
|
||||
check_epoll_wait::<1>(epfd, &[Ev { events: libc::EPOLLOUT as _, data: fds[0] }], 0);
|
||||
|
||||
// epoll_wait timeouts without notification.
|
||||
check_epoll_wait::<1>(epfd, &[], 10);
|
||||
|
||||
// Trigger epoll notification after timeout.
|
||||
let data = "abcde".as_bytes().as_ptr();
|
||||
let res = unsafe { libc_utils::write_all(fds[1], data as *const libc::c_void, 5) };
|
||||
assert_eq!(res, 5);
|
||||
write_all_from_slice(fds[1], b"abcde").unwrap();
|
||||
|
||||
// Check the result of the notification.
|
||||
let expected_event = u32::try_from(libc::EPOLLIN | libc::EPOLLOUT).unwrap();
|
||||
let expected_value = fds[0] as u64;
|
||||
check_epoll_wait::<1>(epfd, &[(expected_event, expected_value)], 10);
|
||||
check_epoll_wait::<1>(
|
||||
epfd,
|
||||
&[Ev { events: (libc::EPOLLIN | libc::EPOLLOUT) as _, data: fds[0] }],
|
||||
10,
|
||||
);
|
||||
}
|
||||
|
||||
// This test shows a data_race before epoll had vector clocks added.
|
||||
fn test_epoll_race() {
|
||||
// Create an epoll instance.
|
||||
let epfd = unsafe { libc::epoll_create1(0) };
|
||||
assert_ne!(epfd, -1);
|
||||
let epfd = errno_result(unsafe { libc::epoll_create1(0) }).unwrap();
|
||||
|
||||
// Create an eventfd instance.
|
||||
let flags = libc::EFD_NONBLOCK | libc::EFD_CLOEXEC;
|
||||
let fd = unsafe { libc::eventfd(0, flags) };
|
||||
let fd = errno_result(unsafe { libc::eventfd(0, flags) }).unwrap();
|
||||
|
||||
// Register eventfd with the epoll instance.
|
||||
let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: fd as u64 };
|
||||
let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fd, &mut ev) };
|
||||
assert_eq!(res, 0);
|
||||
epoll_ctl_add(epfd, fd, EPOLL_IN_OUT_ET).unwrap();
|
||||
|
||||
static mut VAL: u8 = 0;
|
||||
let thread1 = thread::spawn(move || {
|
||||
// Write to the static mut variable.
|
||||
unsafe { VAL = 1 };
|
||||
// Write to the eventfd instance.
|
||||
let sized_8_data: [u8; 8] = 1_u64.to_ne_bytes();
|
||||
let res = unsafe { libc::write(fd, sized_8_data.as_ptr() as *const libc::c_void, 8) };
|
||||
// write returns number of bytes written, which is always 8.
|
||||
assert_eq!(res, 8);
|
||||
write_all_from_slice(fd, &1_u64.to_ne_bytes()).unwrap();
|
||||
});
|
||||
thread::yield_now();
|
||||
// epoll_wait for the event to happen.
|
||||
let expected_event = u32::try_from(libc::EPOLLIN | libc::EPOLLOUT).unwrap();
|
||||
let expected_value = u64::try_from(fd).unwrap();
|
||||
check_epoll_wait::<8>(epfd, &[(expected_event, expected_value)], -1);
|
||||
check_epoll_wait::<8>(
|
||||
epfd,
|
||||
&[Ev { events: (libc::EPOLLIN | libc::EPOLLOUT) as _, data: fd }],
|
||||
-1,
|
||||
);
|
||||
// Read from the static mut variable.
|
||||
#[allow(static_mut_refs)]
|
||||
unsafe {
|
||||
|
|
@ -177,35 +138,28 @@ fn test_epoll_race() {
|
|||
/// epoll it is blocked on.
|
||||
fn wakeup_on_new_interest() {
|
||||
// Create an epoll instance.
|
||||
let epfd = unsafe { libc::epoll_create1(0) };
|
||||
assert_ne!(epfd, -1);
|
||||
let epfd = errno_result(unsafe { libc::epoll_create1(0) }).unwrap();
|
||||
|
||||
// Create a socketpair instance.
|
||||
let mut fds = [-1, -1];
|
||||
let res = unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) };
|
||||
assert_eq!(res, 0);
|
||||
errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) });
|
||||
|
||||
// Write to fd[0]
|
||||
let data = "abcde".as_bytes().as_ptr();
|
||||
let res = unsafe { libc_utils::write_all(fds[0], data as *const libc::c_void, 5) };
|
||||
assert_eq!(res, 5);
|
||||
write_all_from_slice(fds[0], b"abcde").unwrap();
|
||||
|
||||
// Block a thread on the epoll instance.
|
||||
let t = std::thread::spawn(move || {
|
||||
let expected_event = u32::try_from(libc::EPOLLIN | libc::EPOLLOUT).unwrap();
|
||||
let expected_value = u64::try_from(fds[1]).unwrap();
|
||||
check_epoll_wait::<8>(epfd, &[(expected_event, expected_value)], -1);
|
||||
check_epoll_wait::<8>(
|
||||
epfd,
|
||||
&[Ev { events: (libc::EPOLLIN | libc::EPOLLOUT) as _, data: fds[1] }],
|
||||
-1,
|
||||
);
|
||||
});
|
||||
// Ensure the thread is blocked.
|
||||
std::thread::yield_now();
|
||||
|
||||
// Register fd[1] with EPOLLIN|EPOLLOUT|EPOLLET|EPOLLRDHUP
|
||||
let mut ev = libc::epoll_event {
|
||||
events: (libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET | libc::EPOLLRDHUP) as _,
|
||||
u64: u64::try_from(fds[1]).unwrap(),
|
||||
};
|
||||
let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fds[1], &mut ev) };
|
||||
assert_eq!(res, 0);
|
||||
epoll_ctl_add(epfd, fds[1], EPOLL_IN_OUT_ET | libc::EPOLLRDHUP as i32).unwrap();
|
||||
|
||||
// This should wake up the thread.
|
||||
t.join().unwrap();
|
||||
|
|
@ -215,25 +169,23 @@ fn wakeup_on_new_interest() {
|
|||
/// to consume them all.
|
||||
fn multiple_events_wake_multiple_threads() {
|
||||
// Create an epoll instance.
|
||||
let epfd = unsafe { libc::epoll_create1(0) };
|
||||
assert_ne!(epfd, -1);
|
||||
let epfd = errno_result(unsafe { libc::epoll_create1(0) }).unwrap();
|
||||
|
||||
// Create an eventfd instance.
|
||||
let flags = libc::EFD_NONBLOCK | libc::EFD_CLOEXEC;
|
||||
let fd1 = unsafe { libc::eventfd(0, flags) };
|
||||
let fd1 = errno_result(unsafe { libc::eventfd(0, flags) }).unwrap();
|
||||
// Make a duplicate so that we have two file descriptors for the same file description.
|
||||
let fd2 = unsafe { libc::dup(fd1) };
|
||||
let fd2 = errno_result(unsafe { libc::dup(fd1) }).unwrap();
|
||||
|
||||
// Register both with epoll.
|
||||
let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: fd1 as u64 };
|
||||
let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fd1, &mut ev) };
|
||||
assert_eq!(res, 0);
|
||||
let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: fd2 as u64 };
|
||||
let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fd2, &mut ev) };
|
||||
assert_eq!(res, 0);
|
||||
epoll_ctl_add(epfd, fd1, EPOLL_IN_OUT_ET).unwrap();
|
||||
epoll_ctl_add(epfd, fd2, EPOLL_IN_OUT_ET).unwrap();
|
||||
|
||||
// Consume the initial events.
|
||||
let expected = [(libc::EPOLLOUT as u32, fd1 as u64), (libc::EPOLLOUT as u32, fd2 as u64)];
|
||||
let expected = [
|
||||
Ev { events: libc::EPOLLOUT as _, data: fd1 },
|
||||
Ev { events: libc::EPOLLOUT as _, data: fd2 },
|
||||
];
|
||||
check_epoll_wait::<8>(epfd, &expected, -1);
|
||||
|
||||
// Block two threads on the epoll, both wanting to get just one event.
|
||||
|
|
@ -241,19 +193,19 @@ fn multiple_events_wake_multiple_threads() {
|
|||
let mut e = libc::epoll_event { events: 0, u64: 0 };
|
||||
let res = unsafe { libc::epoll_wait(epfd, &raw mut e, 1, -1) };
|
||||
assert!(res == 1);
|
||||
(e.events, e.u64)
|
||||
Ev { events: e.events.cast_signed(), data: e.u64.try_into().unwrap() }
|
||||
});
|
||||
let t2 = thread::spawn(move || {
|
||||
let mut e = libc::epoll_event { events: 0, u64: 0 };
|
||||
let res = unsafe { libc::epoll_wait(epfd, &raw mut e, 1, -1) };
|
||||
assert!(res == 1);
|
||||
(e.events, e.u64)
|
||||
Ev { events: e.events.cast_signed(), data: e.u64.try_into().unwrap() }
|
||||
});
|
||||
// Yield so both threads are waiting now.
|
||||
thread::yield_now();
|
||||
|
||||
// Trigger the eventfd. This triggers two events at once!
|
||||
libc_utils::write_all_from_slice(fd1, &0_u64.to_ne_bytes()).unwrap();
|
||||
write_all_from_slice(fd1, &0_u64.to_ne_bytes()).unwrap();
|
||||
|
||||
// Both threads should have been woken up so that both events can be consumed.
|
||||
let e1 = t1.join().unwrap();
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ fn test_epoll_socketpair() {
|
|||
errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) });
|
||||
|
||||
// Write to fd[0]
|
||||
write_all_from_slice(fds[0], "abcde".as_bytes()).unwrap();
|
||||
write_all_from_slice(fds[0], b"abcde").unwrap();
|
||||
|
||||
// Register fd[1] with EPOLLIN|EPOLLOUT|EPOLLET|EPOLLRDHUP
|
||||
epoll_ctl_add(epfd, fds[1], EPOLLIN | EPOLLOUT | EPOLLET | EPOLLRDHUP).unwrap();
|
||||
|
|
@ -72,7 +72,7 @@ fn test_epoll_socketpair() {
|
|||
check_epoll_wait_noblock::<8>(epfd, &[]);
|
||||
|
||||
// Write some more to fd[0].
|
||||
write_all_from_slice(fds[0], "abcde".as_bytes()).unwrap();
|
||||
write_all_from_slice(fds[0], b"abcde").unwrap();
|
||||
|
||||
// This did not change the readiness of fd[1], so we should get no event.
|
||||
// However, Linux seems to always deliver spurious events to the peer on each write,
|
||||
|
|
@ -140,7 +140,7 @@ fn test_epoll_ctl_del() {
|
|||
errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) });
|
||||
|
||||
// Write to fd[0]
|
||||
let data = "abcde".as_bytes().as_ptr();
|
||||
let data = b"abcde".as_ptr();
|
||||
let res = unsafe { libc_utils::write_all(fds[0], data as *const libc::c_void, 5) };
|
||||
assert_eq!(res, 5);
|
||||
|
||||
|
|
@ -168,7 +168,7 @@ fn test_two_epoll_instance() {
|
|||
errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) });
|
||||
|
||||
// Write to the socketpair.
|
||||
let data = "abcde".as_bytes().as_ptr();
|
||||
let data = b"abcde".as_ptr();
|
||||
let res = unsafe { libc_utils::write_all(fds[0], data as *const libc::c_void, 5) };
|
||||
assert_eq!(res, 5);
|
||||
|
||||
|
|
@ -208,7 +208,7 @@ fn test_two_same_fd_in_same_epoll_instance() {
|
|||
assert_eq!(res, 0);
|
||||
|
||||
// Write to the socketpair.
|
||||
let data = "abcde".as_bytes().as_ptr();
|
||||
let data = b"abcde".as_ptr();
|
||||
let res = unsafe { libc_utils::write_all(fds[0], data as *const libc::c_void, 5) };
|
||||
assert_eq!(res, 5);
|
||||
|
||||
|
|
@ -288,7 +288,7 @@ fn test_epoll_socketpair_both_sides() {
|
|||
// Write to fds[1].
|
||||
// (We do the write after the register here, unlike in `test_epoll_socketpair`, to ensure
|
||||
// we cover both orders in which this could be done.)
|
||||
let data = "abcde".as_bytes().as_ptr();
|
||||
let data = b"abcde".as_ptr();
|
||||
let res = unsafe { libc_utils::write_all(fds[1], data as *const libc::c_void, 5) };
|
||||
assert_eq!(res, 5);
|
||||
|
||||
|
|
@ -307,7 +307,7 @@ fn test_epoll_socketpair_both_sides() {
|
|||
let res =
|
||||
unsafe { libc_utils::read_all(fds[0], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) };
|
||||
assert_eq!(res, 5);
|
||||
assert_eq!(buf, "abcde".as_bytes());
|
||||
assert_eq!(buf, *b"abcde");
|
||||
|
||||
// The state of fds[1] does not change (was writable, is writable).
|
||||
// However, we force a spurious wakeup as the read buffer just got emptied.
|
||||
|
|
@ -500,7 +500,7 @@ fn test_no_notification_for_unregister_flag() {
|
|||
assert_eq!(res, 0);
|
||||
|
||||
// Write to fd[1].
|
||||
let data = "abcde".as_bytes().as_ptr();
|
||||
let data = b"abcde".as_ptr();
|
||||
let res: i32 = unsafe {
|
||||
libc_utils::write_all(fds[1], data as *const libc::c_void, 5).try_into().unwrap()
|
||||
};
|
||||
|
|
@ -534,7 +534,7 @@ fn test_socketpair_epollerr() {
|
|||
errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) });
|
||||
|
||||
// Write to fd[0]
|
||||
let data = "abcde".as_bytes().as_ptr();
|
||||
let data = b"abcde".as_ptr();
|
||||
let res = unsafe { libc_utils::write_all(fds[0], data as *const libc::c_void, 5) };
|
||||
assert_eq!(res, 5);
|
||||
|
||||
|
|
@ -747,7 +747,7 @@ fn test_issue_4374_reads() {
|
|||
assert_eq!(unsafe { libc::fcntl(fds[1], libc::F_SETFL, libc::O_NONBLOCK) }, 0);
|
||||
|
||||
// Write to fds[1] so that fds[0] becomes readable.
|
||||
let data = "abcde".as_bytes().as_ptr();
|
||||
let data = b"abcde".as_ptr();
|
||||
let res: i32 = unsafe {
|
||||
libc_utils::write_all(fds[1], data as *const libc::c_void, 5).try_into().unwrap()
|
||||
};
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ pub mod epoll {
|
|||
|
||||
/// The libc epoll_event type doesn't fit to the EPOLLIN etc constants, so we have our
|
||||
/// own type. We also make the data field an int since we typically want to store FDs there.
|
||||
#[derive(PartialEq, Debug)]
|
||||
#[derive(PartialEq, Debug, Clone, Copy)]
|
||||
pub struct Ev {
|
||||
pub events: c_int,
|
||||
pub data: c_int,
|
||||
|
|
@ -138,10 +138,10 @@ pub mod epoll {
|
|||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn check_epoll_wait_noblock<const N: usize>(epfd: i32, expected: &[Ev]) {
|
||||
pub fn check_epoll_wait<const N: usize>(epfd: i32, expected: &[Ev], timeout: i32) {
|
||||
let mut array: [libc::epoll_event; N] = [libc::epoll_event { events: 0, u64: 0 }; N];
|
||||
let num = errno_result(unsafe {
|
||||
libc::epoll_wait(epfd, array.as_mut_ptr(), N.try_into().unwrap(), 0)
|
||||
libc::epoll_wait(epfd, array.as_mut_ptr(), N.try_into().unwrap(), timeout)
|
||||
})
|
||||
.expect("epoll_wait returned an error");
|
||||
let got = &mut array[..num.try_into().unwrap()];
|
||||
|
|
@ -151,4 +151,9 @@ pub mod epoll {
|
|||
.collect::<Vec<_>>();
|
||||
assert_eq!(got, expected, "got wrong notifications");
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn check_epoll_wait_noblock<const N: usize>(epfd: i32, expected: &[Ev]) {
|
||||
check_epoll_wait::<N>(epfd, expected, 0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue