mirror of https://github.com/smol-rs/polling
Add edge/oneshot combination mode (#96)
This commit is contained in:
parent
e340458d3a
commit
0f38ed35ea
|
@ -222,6 +222,7 @@ impl Poller {
|
|||
PollMode::Oneshot => libc::EPOLLONESHOT,
|
||||
PollMode::Level => 0,
|
||||
PollMode::Edge => libc::EPOLLET,
|
||||
PollMode::EdgeOneshot => libc::EPOLLONESHOT | libc::EPOLLET,
|
||||
};
|
||||
if ev.readable {
|
||||
flags |= read_flags();
|
||||
|
|
|
@ -146,7 +146,7 @@ impl Poller {
|
|||
);
|
||||
|
||||
// We don't support edge-triggered events.
|
||||
if matches!(mode, PollMode::Edge) {
|
||||
if matches!(mode, PollMode::Edge | PollMode::EdgeOneshot) {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"edge-triggered events are not supported",
|
||||
|
@ -206,7 +206,7 @@ impl Poller {
|
|||
);
|
||||
|
||||
// We don't support edge-triggered events.
|
||||
if matches!(mode, PollMode::Edge) {
|
||||
if matches!(mode, PollMode::Edge | PollMode::EdgeOneshot) {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"edge-triggered events are not supported",
|
||||
|
|
|
@ -251,6 +251,7 @@ pub(crate) fn mode_to_flags(mode: PollMode) -> FilterFlags {
|
|||
PollMode::Oneshot => libc::EV_ONESHOT,
|
||||
PollMode::Level => 0,
|
||||
PollMode::Edge => libc::EV_CLEAR,
|
||||
PollMode::EdgeOneshot => libc::EV_ONESHOT | libc::EV_CLEAR,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
10
src/lib.rs
10
src/lib.rs
|
@ -168,6 +168,16 @@ pub enum PollMode {
|
|||
/// this mode in an unsupported operating system will raise an error. You can check if
|
||||
/// the operating system supports this mode by calling `Poller::supports_edge`.
|
||||
Edge,
|
||||
|
||||
/// Poll in both edge-triggered and oneshot mode.
|
||||
///
|
||||
/// This mode is similar to the `Oneshot` mode, but it will only deliver one event per new
|
||||
/// event.
|
||||
///
|
||||
/// Not all operating system support this mode. Trying to register a file descriptor with
|
||||
/// this mode in an unsupported operating system will raise an error. You can check if
|
||||
/// the operating system supports this mode by calling `Poller::supports_edge`.
|
||||
EdgeOneshot,
|
||||
}
|
||||
|
||||
impl Event {
|
||||
|
|
|
@ -416,7 +416,7 @@ fn cvt_mode_as_remove(mode: PollMode) -> io::Result<bool> {
|
|||
match mode {
|
||||
PollMode::Oneshot => Ok(true),
|
||||
PollMode::Level => Ok(false),
|
||||
PollMode::Edge => Err(crate::unsupported_error(
|
||||
_ => Err(crate::unsupported_error(
|
||||
"edge-triggered I/O events are not supported in poll()",
|
||||
)),
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ impl Poller {
|
|||
flags |= libc::POLLOUT;
|
||||
}
|
||||
|
||||
if let PollMode::Edge | PollMode::Level = mode {
|
||||
if mode != PollMode::Oneshot {
|
||||
return Err(crate::unsupported_error(
|
||||
"this kind of event is not supported with event ports",
|
||||
));
|
||||
|
|
|
@ -162,6 +162,81 @@ fn edge_triggered() {
|
|||
assert_eq!(events, [Event::readable(reader_token)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn edge_oneshot_triggered() {
|
||||
// Create our streams.
|
||||
let (mut reader, mut writer) = tcp_pair().unwrap();
|
||||
let reader_token = 1;
|
||||
|
||||
// Create our poller and register our streams.
|
||||
let poller = Poller::new().unwrap();
|
||||
if poller
|
||||
.add_with_mode(
|
||||
&reader,
|
||||
Event::readable(reader_token),
|
||||
PollMode::EdgeOneshot,
|
||||
)
|
||||
.is_err()
|
||||
{
|
||||
// Only panic if we're on a platform that should support level mode.
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(all(
|
||||
any(
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "tvos",
|
||||
target_os = "watchos",
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "dragonfly"
|
||||
),
|
||||
not(polling_test_poll_backend)
|
||||
))] {
|
||||
panic!("Edge mode should be supported on this platform");
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write some data to the writer.
|
||||
let data = [1, 2, 3, 4, 5];
|
||||
writer.write_all(&data).unwrap();
|
||||
|
||||
// A "readable" notification should be delivered.
|
||||
let mut events = Vec::new();
|
||||
poller
|
||||
.wait(&mut events, Some(Duration::from_secs(10)))
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(events, [Event::readable(reader_token)]);
|
||||
|
||||
// If we read some of the data, the notification should not still be available.
|
||||
reader.read_exact(&mut [0; 3]).unwrap();
|
||||
events.clear();
|
||||
poller
|
||||
.wait(&mut events, Some(Duration::from_secs(0)))
|
||||
.unwrap();
|
||||
assert_eq!(events, []);
|
||||
|
||||
// If we modify to re-enable the notification, it should be delivered.
|
||||
poller
|
||||
.modify_with_mode(
|
||||
&reader,
|
||||
Event::readable(reader_token),
|
||||
PollMode::EdgeOneshot,
|
||||
)
|
||||
.unwrap();
|
||||
events.clear();
|
||||
poller
|
||||
.wait(&mut events, Some(Duration::from_secs(0)))
|
||||
.unwrap();
|
||||
assert_eq!(events, [Event::readable(reader_token)]);
|
||||
}
|
||||
|
||||
fn tcp_pair() -> io::Result<(TcpStream, TcpStream)> {
|
||||
let listener = TcpListener::bind("127.0.0.1:0")?;
|
||||
let a = TcpStream::connect(listener.local_addr()?)?;
|
||||
|
|
Loading…
Reference in New Issue