2020-08-06 13:02:59 +00:00
|
|
|
//! Bindings to wepoll (Windows).
|
|
|
|
|
|
|
|
use std::convert::TryInto;
|
|
|
|
use std::io;
|
2022-11-29 13:12:39 +00:00
|
|
|
use std::os::raw::c_int;
|
2022-08-18 16:52:28 +00:00
|
|
|
use std::os::windows::io::{AsRawHandle, RawHandle, RawSocket};
|
2020-08-06 13:02:59 +00:00
|
|
|
use std::ptr;
|
2020-10-02 16:31:00 +00:00
|
|
|
use std::sync::atomic::{AtomicBool, Ordering};
|
|
|
|
use std::time::{Duration, Instant};
|
2020-08-06 13:02:59 +00:00
|
|
|
|
2022-08-18 16:52:28 +00:00
|
|
|
#[cfg(not(polling_no_io_safety))]
|
|
|
|
use std::os::windows::io::{AsHandle, BorrowedHandle};
|
|
|
|
|
2021-05-26 05:56:05 +00:00
|
|
|
use wepoll_ffi as we;
|
2020-08-06 13:02:59 +00:00
|
|
|
|
2022-12-30 22:43:47 +00:00
|
|
|
use crate::{Event, PollMode};
|
2020-08-06 13:02:59 +00:00
|
|
|
|
|
|
|
/// Calls a wepoll function and results in `io::Result`.
|
|
|
|
macro_rules! wepoll {
|
|
|
|
($fn:ident $args:tt) => {{
|
|
|
|
let res = unsafe { we::$fn $args };
|
|
|
|
if res == -1 {
|
|
|
|
Err(std::io::Error::last_os_error())
|
|
|
|
} else {
|
|
|
|
Ok(res)
|
|
|
|
}
|
|
|
|
}};
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Interface to wepoll.
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct Poller {
|
|
|
|
handle: we::HANDLE,
|
2020-10-02 16:31:00 +00:00
|
|
|
notified: AtomicBool,
|
2020-08-06 13:02:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
unsafe impl Send for Poller {}
|
|
|
|
unsafe impl Sync for Poller {}
|
|
|
|
|
|
|
|
impl Poller {
|
|
|
|
/// Creates a new poller.
|
|
|
|
pub fn new() -> io::Result<Poller> {
|
|
|
|
let handle = unsafe { we::epoll_create1(0) };
|
|
|
|
if handle.is_null() {
|
2022-12-30 22:43:47 +00:00
|
|
|
return Err(crate::unsupported_error(
|
2022-12-01 04:26:28 +00:00
|
|
|
format!(
|
|
|
|
"Failed to initialize Wepoll: {}\nThis usually only happens for old Windows or Wine.",
|
|
|
|
io::Error::last_os_error()
|
|
|
|
)
|
|
|
|
));
|
2020-08-06 13:02:59 +00:00
|
|
|
}
|
2020-10-02 16:31:00 +00:00
|
|
|
let notified = AtomicBool::new(false);
|
2020-09-03 10:55:46 +00:00
|
|
|
log::trace!("new: handle={:?}", handle);
|
2020-10-02 16:31:00 +00:00
|
|
|
Ok(Poller { handle, notified })
|
2020-08-06 13:02:59 +00:00
|
|
|
}
|
|
|
|
|
2022-12-30 22:43:47 +00:00
|
|
|
/// Whether this poller supports level-triggered events.
|
|
|
|
pub fn supports_level(&self) -> bool {
|
|
|
|
true
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Whether this poller supports edge-triggered events.
|
|
|
|
pub fn supports_edge(&self) -> bool {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
|
Separate adding and modifying of file descriptors
This replaces Poller.insert() and Poller.interest() with Poller.add()
and Poller.modify(), and renames Poller.remove() to Poller.delete().
The method Poller.add() is used for adding a new file descriptor, while
Poller.modify() is used for updating an existing one. Poller.remove() is
renamed to Poller.delete() so the naming scheme of these methods follows
that of epoll, wepoll, etc.
This new setup means that adding a new socket only requires a single
call of Poller.add(), instead of a combination of Poller.insert() and
Poller.interest(). This reduces the amount of system calls necessary,
and leads to a more pleasant API.
On systems that use kqueue or ports, the behaviour of Poller.add() and
Poller.modify() is the same. This is because on these systems adding an
already existing file descriptor will just update its configuration.
This however is an implementation detail and should not be relied upon
by users.
Migrating to this new API is pretty simple, simply replace this:
poller.insert(&socket);
poller.interest(&socket, event);
With this:
poller.add(&socket, event);
And for cases where Poller.interest() was used for updating an existing
file descriptor, simply replace it will a call to Poller.modify().
See https://github.com/stjepang/polling/issues/16 and
https://github.com/stjepang/polling/pull/17 for more information.
2020-10-01 19:26:44 +00:00
|
|
|
/// Adds a socket.
|
2022-12-30 22:43:47 +00:00
|
|
|
pub fn add(&self, sock: RawSocket, ev: Event, mode: PollMode) -> io::Result<()> {
|
Separate adding and modifying of file descriptors
This replaces Poller.insert() and Poller.interest() with Poller.add()
and Poller.modify(), and renames Poller.remove() to Poller.delete().
The method Poller.add() is used for adding a new file descriptor, while
Poller.modify() is used for updating an existing one. Poller.remove() is
renamed to Poller.delete() so the naming scheme of these methods follows
that of epoll, wepoll, etc.
This new setup means that adding a new socket only requires a single
call of Poller.add(), instead of a combination of Poller.insert() and
Poller.interest(). This reduces the amount of system calls necessary,
and leads to a more pleasant API.
On systems that use kqueue or ports, the behaviour of Poller.add() and
Poller.modify() is the same. This is because on these systems adding an
already existing file descriptor will just update its configuration.
This however is an implementation detail and should not be relied upon
by users.
Migrating to this new API is pretty simple, simply replace this:
poller.insert(&socket);
poller.interest(&socket, event);
With this:
poller.add(&socket, event);
And for cases where Poller.interest() was used for updating an existing
file descriptor, simply replace it will a call to Poller.modify().
See https://github.com/stjepang/polling/issues/16 and
https://github.com/stjepang/polling/pull/17 for more information.
2020-10-01 19:26:44 +00:00
|
|
|
log::trace!("add: handle={:?}, sock={}, ev={:?}", self.handle, sock, ev);
|
2022-12-30 22:43:47 +00:00
|
|
|
self.ctl(we::EPOLL_CTL_ADD, sock, Some((ev, mode)))
|
2020-08-06 13:02:59 +00:00
|
|
|
}
|
|
|
|
|
Separate adding and modifying of file descriptors
This replaces Poller.insert() and Poller.interest() with Poller.add()
and Poller.modify(), and renames Poller.remove() to Poller.delete().
The method Poller.add() is used for adding a new file descriptor, while
Poller.modify() is used for updating an existing one. Poller.remove() is
renamed to Poller.delete() so the naming scheme of these methods follows
that of epoll, wepoll, etc.
This new setup means that adding a new socket only requires a single
call of Poller.add(), instead of a combination of Poller.insert() and
Poller.interest(). This reduces the amount of system calls necessary,
and leads to a more pleasant API.
On systems that use kqueue or ports, the behaviour of Poller.add() and
Poller.modify() is the same. This is because on these systems adding an
already existing file descriptor will just update its configuration.
This however is an implementation detail and should not be relied upon
by users.
Migrating to this new API is pretty simple, simply replace this:
poller.insert(&socket);
poller.interest(&socket, event);
With this:
poller.add(&socket, event);
And for cases where Poller.interest() was used for updating an existing
file descriptor, simply replace it will a call to Poller.modify().
See https://github.com/stjepang/polling/issues/16 and
https://github.com/stjepang/polling/pull/17 for more information.
2020-10-01 19:26:44 +00:00
|
|
|
/// Modifies a socket.
|
2022-12-30 22:43:47 +00:00
|
|
|
pub fn modify(&self, sock: RawSocket, ev: Event, mode: PollMode) -> io::Result<()> {
|
2020-09-03 10:55:46 +00:00
|
|
|
log::trace!(
|
Separate adding and modifying of file descriptors
This replaces Poller.insert() and Poller.interest() with Poller.add()
and Poller.modify(), and renames Poller.remove() to Poller.delete().
The method Poller.add() is used for adding a new file descriptor, while
Poller.modify() is used for updating an existing one. Poller.remove() is
renamed to Poller.delete() so the naming scheme of these methods follows
that of epoll, wepoll, etc.
This new setup means that adding a new socket only requires a single
call of Poller.add(), instead of a combination of Poller.insert() and
Poller.interest(). This reduces the amount of system calls necessary,
and leads to a more pleasant API.
On systems that use kqueue or ports, the behaviour of Poller.add() and
Poller.modify() is the same. This is because on these systems adding an
already existing file descriptor will just update its configuration.
This however is an implementation detail and should not be relied upon
by users.
Migrating to this new API is pretty simple, simply replace this:
poller.insert(&socket);
poller.interest(&socket, event);
With this:
poller.add(&socket, event);
And for cases where Poller.interest() was used for updating an existing
file descriptor, simply replace it will a call to Poller.modify().
See https://github.com/stjepang/polling/issues/16 and
https://github.com/stjepang/polling/pull/17 for more information.
2020-10-01 19:26:44 +00:00
|
|
|
"modify: handle={:?}, sock={}, ev={:?}",
|
2020-08-29 14:00:59 +00:00
|
|
|
self.handle,
|
|
|
|
sock,
|
|
|
|
ev
|
|
|
|
);
|
2022-12-30 22:43:47 +00:00
|
|
|
self.ctl(we::EPOLL_CTL_MOD, sock, Some((ev, mode)))
|
2020-08-06 13:02:59 +00:00
|
|
|
}
|
|
|
|
|
2020-10-02 14:40:09 +00:00
|
|
|
/// Deletes a socket.
|
Separate adding and modifying of file descriptors
This replaces Poller.insert() and Poller.interest() with Poller.add()
and Poller.modify(), and renames Poller.remove() to Poller.delete().
The method Poller.add() is used for adding a new file descriptor, while
Poller.modify() is used for updating an existing one. Poller.remove() is
renamed to Poller.delete() so the naming scheme of these methods follows
that of epoll, wepoll, etc.
This new setup means that adding a new socket only requires a single
call of Poller.add(), instead of a combination of Poller.insert() and
Poller.interest(). This reduces the amount of system calls necessary,
and leads to a more pleasant API.
On systems that use kqueue or ports, the behaviour of Poller.add() and
Poller.modify() is the same. This is because on these systems adding an
already existing file descriptor will just update its configuration.
This however is an implementation detail and should not be relied upon
by users.
Migrating to this new API is pretty simple, simply replace this:
poller.insert(&socket);
poller.interest(&socket, event);
With this:
poller.add(&socket, event);
And for cases where Poller.interest() was used for updating an existing
file descriptor, simply replace it will a call to Poller.modify().
See https://github.com/stjepang/polling/issues/16 and
https://github.com/stjepang/polling/pull/17 for more information.
2020-10-01 19:26:44 +00:00
|
|
|
pub fn delete(&self, sock: RawSocket) -> io::Result<()> {
|
2020-09-03 10:55:46 +00:00
|
|
|
log::trace!("remove: handle={:?}, sock={}", self.handle, sock);
|
2020-10-02 14:40:09 +00:00
|
|
|
self.ctl(we::EPOLL_CTL_DEL, sock, None)
|
2020-08-06 13:02:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Waits for I/O events with an optional timeout.
|
|
|
|
///
|
|
|
|
/// Returns the number of processed I/O events.
|
|
|
|
///
|
|
|
|
/// If a notification occurs, this method will return but the notification event will not be
|
|
|
|
/// included in the `events` list nor contribute to the returned count.
|
2020-08-14 12:38:02 +00:00
|
|
|
pub fn wait(&self, events: &mut Events, timeout: Option<Duration>) -> io::Result<()> {
|
2020-09-03 10:55:46 +00:00
|
|
|
log::trace!("wait: handle={:?}, timeout={:?}", self.handle, timeout);
|
2023-01-08 03:35:46 +00:00
|
|
|
let deadline = timeout.and_then(|t| Instant::now().checked_add(t));
|
2020-10-02 15:39:57 +00:00
|
|
|
|
2020-10-02 16:31:00 +00:00
|
|
|
loop {
|
|
|
|
// Convert the timeout to milliseconds.
|
|
|
|
let timeout_ms = match deadline.map(|d| d.saturating_duration_since(Instant::now())) {
|
|
|
|
None => -1,
|
|
|
|
Some(t) => {
|
|
|
|
// Round up to a whole millisecond.
|
|
|
|
let mut ms = t.as_millis().try_into().unwrap_or(std::u64::MAX);
|
|
|
|
if Duration::from_millis(ms) < t {
|
2021-05-26 09:33:24 +00:00
|
|
|
ms = ms.saturating_add(1);
|
2020-10-02 16:31:00 +00:00
|
|
|
}
|
|
|
|
ms.try_into().unwrap_or(std::i32::MAX)
|
2020-08-14 14:02:30 +00:00
|
|
|
}
|
2020-10-02 16:31:00 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// Wait for I/O events.
|
|
|
|
events.len = wepoll!(epoll_wait(
|
|
|
|
self.handle,
|
|
|
|
events.list.as_mut_ptr(),
|
2022-11-27 04:50:12 +00:00
|
|
|
events.list.len() as c_int,
|
2020-10-02 16:31:00 +00:00
|
|
|
timeout_ms,
|
|
|
|
))? as usize;
|
|
|
|
log::trace!("new events: handle={:?}, len={}", self.handle, events.len);
|
|
|
|
|
|
|
|
// Break if there was a notification or at least one event, or if deadline is reached.
|
|
|
|
if self.notified.swap(false, Ordering::SeqCst) || events.len > 0 || timeout_ms == 0 {
|
|
|
|
break;
|
2020-08-14 14:33:28 +00:00
|
|
|
}
|
2020-10-02 16:31:00 +00:00
|
|
|
}
|
2020-08-06 13:02:59 +00:00
|
|
|
|
2020-08-14 12:38:02 +00:00
|
|
|
Ok(())
|
2020-08-06 13:02:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Sends a notification to wake up the current or next `wait()` call.
|
|
|
|
pub fn notify(&self) -> io::Result<()> {
|
2020-09-03 10:55:46 +00:00
|
|
|
log::trace!("notify: handle={:?}", self.handle);
|
2020-10-02 16:31:00 +00:00
|
|
|
|
2020-12-24 12:18:55 +00:00
|
|
|
if self
|
2020-10-02 16:31:00 +00:00
|
|
|
.notified
|
2020-12-24 12:18:55 +00:00
|
|
|
.compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst)
|
|
|
|
.is_ok()
|
2020-10-02 16:31:00 +00:00
|
|
|
{
|
|
|
|
unsafe {
|
|
|
|
// This call errors if a notification has already been posted, but that's okay - we
|
|
|
|
// can just ignore the error.
|
|
|
|
//
|
|
|
|
// The original wepoll does not support notifications triggered this way, which is
|
|
|
|
// why wepoll-sys includes a small patch to support them.
|
2022-11-27 04:50:12 +00:00
|
|
|
windows_sys::Win32::System::IO::PostQueuedCompletionStatus(
|
|
|
|
self.handle as _,
|
2020-10-02 16:31:00 +00:00
|
|
|
0,
|
|
|
|
0,
|
|
|
|
ptr::null_mut(),
|
|
|
|
);
|
|
|
|
}
|
2020-08-06 13:02:59 +00:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
Separate adding and modifying of file descriptors
This replaces Poller.insert() and Poller.interest() with Poller.add()
and Poller.modify(), and renames Poller.remove() to Poller.delete().
The method Poller.add() is used for adding a new file descriptor, while
Poller.modify() is used for updating an existing one. Poller.remove() is
renamed to Poller.delete() so the naming scheme of these methods follows
that of epoll, wepoll, etc.
This new setup means that adding a new socket only requires a single
call of Poller.add(), instead of a combination of Poller.insert() and
Poller.interest(). This reduces the amount of system calls necessary,
and leads to a more pleasant API.
On systems that use kqueue or ports, the behaviour of Poller.add() and
Poller.modify() is the same. This is because on these systems adding an
already existing file descriptor will just update its configuration.
This however is an implementation detail and should not be relied upon
by users.
Migrating to this new API is pretty simple, simply replace this:
poller.insert(&socket);
poller.interest(&socket, event);
With this:
poller.add(&socket, event);
And for cases where Poller.interest() was used for updating an existing
file descriptor, simply replace it will a call to Poller.modify().
See https://github.com/stjepang/polling/issues/16 and
https://github.com/stjepang/polling/pull/17 for more information.
2020-10-01 19:26:44 +00:00
|
|
|
|
2020-10-02 14:40:09 +00:00
|
|
|
/// Passes arguments to `epoll_ctl`.
|
2022-12-30 22:43:47 +00:00
|
|
|
fn ctl(&self, op: u32, sock: RawSocket, ev: Option<(Event, PollMode)>) -> io::Result<()> {
|
|
|
|
let mut ev = ev
|
|
|
|
.map(|(ev, mode)| {
|
|
|
|
let mut flags = match mode {
|
|
|
|
PollMode::Level => 0,
|
|
|
|
PollMode::Oneshot => we::EPOLLONESHOT,
|
|
|
|
PollMode::Edge => {
|
|
|
|
return Err(crate::unsupported_error(
|
|
|
|
"edge-triggered events are not supported with wepoll",
|
|
|
|
));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
if ev.readable {
|
|
|
|
flags |= READ_FLAGS;
|
|
|
|
}
|
|
|
|
if ev.writable {
|
|
|
|
flags |= WRITE_FLAGS;
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(we::epoll_event {
|
|
|
|
events: flags as u32,
|
|
|
|
data: we::epoll_data {
|
|
|
|
u64_: ev.key as u64,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
})
|
|
|
|
.transpose()?;
|
Separate adding and modifying of file descriptors
This replaces Poller.insert() and Poller.interest() with Poller.add()
and Poller.modify(), and renames Poller.remove() to Poller.delete().
The method Poller.add() is used for adding a new file descriptor, while
Poller.modify() is used for updating an existing one. Poller.remove() is
renamed to Poller.delete() so the naming scheme of these methods follows
that of epoll, wepoll, etc.
This new setup means that adding a new socket only requires a single
call of Poller.add(), instead of a combination of Poller.insert() and
Poller.interest(). This reduces the amount of system calls necessary,
and leads to a more pleasant API.
On systems that use kqueue or ports, the behaviour of Poller.add() and
Poller.modify() is the same. This is because on these systems adding an
already existing file descriptor will just update its configuration.
This however is an implementation detail and should not be relied upon
by users.
Migrating to this new API is pretty simple, simply replace this:
poller.insert(&socket);
poller.interest(&socket, event);
With this:
poller.add(&socket, event);
And for cases where Poller.interest() was used for updating an existing
file descriptor, simply replace it will a call to Poller.modify().
See https://github.com/stjepang/polling/issues/16 and
https://github.com/stjepang/polling/pull/17 for more information.
2020-10-01 19:26:44 +00:00
|
|
|
wepoll!(epoll_ctl(
|
|
|
|
self.handle,
|
2022-11-27 04:50:12 +00:00
|
|
|
op as c_int,
|
Separate adding and modifying of file descriptors
This replaces Poller.insert() and Poller.interest() with Poller.add()
and Poller.modify(), and renames Poller.remove() to Poller.delete().
The method Poller.add() is used for adding a new file descriptor, while
Poller.modify() is used for updating an existing one. Poller.remove() is
renamed to Poller.delete() so the naming scheme of these methods follows
that of epoll, wepoll, etc.
This new setup means that adding a new socket only requires a single
call of Poller.add(), instead of a combination of Poller.insert() and
Poller.interest(). This reduces the amount of system calls necessary,
and leads to a more pleasant API.
On systems that use kqueue or ports, the behaviour of Poller.add() and
Poller.modify() is the same. This is because on these systems adding an
already existing file descriptor will just update its configuration.
This however is an implementation detail and should not be relied upon
by users.
Migrating to this new API is pretty simple, simply replace this:
poller.insert(&socket);
poller.interest(&socket, event);
With this:
poller.add(&socket, event);
And for cases where Poller.interest() was used for updating an existing
file descriptor, simply replace it will a call to Poller.modify().
See https://github.com/stjepang/polling/issues/16 and
https://github.com/stjepang/polling/pull/17 for more information.
2020-10-01 19:26:44 +00:00
|
|
|
sock as we::SOCKET,
|
2020-10-02 14:40:09 +00:00
|
|
|
ev.as_mut()
|
2020-10-02 16:19:15 +00:00
|
|
|
.map(|ev| ev as *mut we::epoll_event)
|
2020-10-02 14:40:09 +00:00
|
|
|
.unwrap_or(ptr::null_mut()),
|
Separate adding and modifying of file descriptors
This replaces Poller.insert() and Poller.interest() with Poller.add()
and Poller.modify(), and renames Poller.remove() to Poller.delete().
The method Poller.add() is used for adding a new file descriptor, while
Poller.modify() is used for updating an existing one. Poller.remove() is
renamed to Poller.delete() so the naming scheme of these methods follows
that of epoll, wepoll, etc.
This new setup means that adding a new socket only requires a single
call of Poller.add(), instead of a combination of Poller.insert() and
Poller.interest(). This reduces the amount of system calls necessary,
and leads to a more pleasant API.
On systems that use kqueue or ports, the behaviour of Poller.add() and
Poller.modify() is the same. This is because on these systems adding an
already existing file descriptor will just update its configuration.
This however is an implementation detail and should not be relied upon
by users.
Migrating to this new API is pretty simple, simply replace this:
poller.insert(&socket);
poller.interest(&socket, event);
With this:
poller.add(&socket, event);
And for cases where Poller.interest() was used for updating an existing
file descriptor, simply replace it will a call to Poller.modify().
See https://github.com/stjepang/polling/issues/16 and
https://github.com/stjepang/polling/pull/17 for more information.
2020-10-01 19:26:44 +00:00
|
|
|
))?;
|
|
|
|
Ok(())
|
|
|
|
}
|
2020-08-06 13:02:59 +00:00
|
|
|
}
|
|
|
|
|
2022-08-18 16:52:28 +00:00
|
|
|
impl AsRawHandle for Poller {
|
|
|
|
fn as_raw_handle(&self) -> RawHandle {
|
|
|
|
self.handle as RawHandle
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(polling_no_io_safety))]
|
|
|
|
impl AsHandle for Poller {
|
|
|
|
fn as_handle(&self) -> BorrowedHandle<'_> {
|
|
|
|
// SAFETY: lifetime is bound by "self"
|
|
|
|
unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-06 13:02:59 +00:00
|
|
|
impl Drop for Poller {
|
|
|
|
fn drop(&mut self) {
|
2020-09-03 10:55:46 +00:00
|
|
|
log::trace!("drop: handle={:?}", self.handle);
|
2020-08-06 13:02:59 +00:00
|
|
|
unsafe {
|
|
|
|
we::epoll_close(self.handle);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Wepoll flags for all possible readability events.
|
|
|
|
const READ_FLAGS: u32 = we::EPOLLIN | we::EPOLLRDHUP | we::EPOLLHUP | we::EPOLLERR | we::EPOLLPRI;
|
|
|
|
|
|
|
|
/// Wepoll flags for all possible writability events.
|
|
|
|
const WRITE_FLAGS: u32 = we::EPOLLOUT | we::EPOLLHUP | we::EPOLLERR;
|
|
|
|
|
|
|
|
/// A list of reported I/O events.
|
|
|
|
pub struct Events {
|
2022-08-21 12:09:43 +00:00
|
|
|
list: Box<[we::epoll_event; 1024]>,
|
2020-08-06 13:02:59 +00:00
|
|
|
len: usize,
|
|
|
|
}
|
|
|
|
|
|
|
|
unsafe impl Send for Events {}
|
|
|
|
|
|
|
|
impl Events {
|
|
|
|
/// Creates an empty list.
|
|
|
|
pub fn new() -> Events {
|
|
|
|
let ev = we::epoll_event {
|
|
|
|
events: 0,
|
2021-05-26 05:56:05 +00:00
|
|
|
data: we::epoll_data { u64_: 0 },
|
2020-08-06 13:02:59 +00:00
|
|
|
};
|
2022-08-21 12:09:43 +00:00
|
|
|
let list = Box::new([ev; 1024]);
|
|
|
|
Events { list, len: 0 }
|
2020-08-06 13:02:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Iterates over I/O events.
|
|
|
|
pub fn iter(&self) -> impl Iterator<Item = Event> + '_ {
|
|
|
|
self.list[..self.len].iter().map(|ev| Event {
|
2021-05-26 05:56:05 +00:00
|
|
|
key: unsafe { ev.data.u64_ } as usize,
|
2020-08-06 13:02:59 +00:00
|
|
|
readable: (ev.events & READ_FLAGS) != 0,
|
|
|
|
writable: (ev.events & WRITE_FLAGS) != 0,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|