Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A way to add EPOLLPRI event type to the epoll selector #1645

Closed
poeschel opened this issue Jan 27, 2023 · 7 comments · Fixed by #1647
Closed

A way to add EPOLLPRI event type to the epoll selector #1645

poeschel opened this issue Jan 27, 2023 · 7 comments · Fixed by #1647

Comments

@poeschel
Copy link
Contributor

While working with Video4Linux2 I am searching for a way to (a)wait POLLPRI events coming from the kernel.
I do see, that an Event can be checked if it is_prioprity:

pub fn is_priority(event: &Event) -> bool {
(event.events as libc::c_int & libc::EPOLLPRI) != 0
}

But I wonder how to register at the Selector in a way that it receives this type of events?
Looking at
pub fn register(&self, fd: RawFd, token: Token, interests: Interest) -> io::Result<()> {
let mut event = libc::epoll_event {
events: interests_to_epoll(interests),
u64: usize::from(token) as u64,
#[cfg(target_os = "redox")]
_pad: 0,
};
syscall!(epoll_ctl(self.ep, libc::EPOLL_CTL_ADD, fd, &mut event)).map(|_| ())
}
it seems, that some kind of PRIORITY Interest would be needed, but it is not there:

mio/src/interest.rs

Lines 19 to 34 in fa4e4b3

// These must be unique.
const READABLE: u8 = 0b0001;
const WRITABLE: u8 = 0b0010;
// The following are not available on all platforms.
#[cfg_attr(
not(any(
target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos"
)),
allow(dead_code)
)]
const AIO: u8 = 0b0100;
#[cfg_attr(not(target_os = "freebsd"), allow(dead_code))]
const LIO: u8 = 0b1000;

I searched a bit through the history and found something similar was already there:

mio/src/event_imp.rs

Lines 613 to 622 in 434405a

// These must be unique.
const EMPTY: u8 = 0b0_000_000;
const READABLE: u8 = 0b0_000_001;
const WRITABLE: u8 = 0b0_000_010;
// The following are not available on all platforms.
const ERROR: u8 = 0b0_000_100;
const HUP: u8 = 0b0_001_000;
const PRIORITY: u8 = 0b0_010_000;
const AIO: u8 = 0b0_100_000;
const LIO: u8 = 0b1_000_000;

But it is gone and I don't know why.
So my questions:

  • Why is the is_priority function there? It is of no use at the moment, right?
  • What happened to the old Ready:PRIORITY? Is there some reason why this got removed or was it a mistake?
  • What would be a good (upstreamable) way to implement the support for POLLPRI type events?
@Thomasdezeeuw
Copy link
Collaborator

EPOLLPRI is enable by default when using readable interest.

@poeschel
Copy link
Contributor Author

EPOLLPRI is enable by default when using readable interest.

Really? I don't see this backed by the code and I do not get any EPOLLPRI events from the kernel.
Have a look here:

fn interests_to_epoll(interests: Interest) -> u32 {
let mut kind = EPOLLET;
if interests.is_readable() {
kind = kind | EPOLLIN | EPOLLRDHUP;
}
if interests.is_writable() {
kind |= EPOLLOUT;
}
kind as u32
}

This sets the event type flags up for the syscall. And it does not set EPOLLPRI.

I made a "horrible hack" here: poeschel@538970c
With this change I do receive the EPOLLPRI events.

@Thomasdezeeuw
Copy link
Collaborator

EPOLLPRI is an output flags only if I recall correctly, so you should see it when use register readable interest. If you want to test this for yourself you can send some Out-Of-Bound (MSG_OOB) data to a TcpStream and you should see an event with EPOLLPRI.

@Urist-McGit
Copy link

Hello, I am working with @poeschel on this problem. We have created a small test project which can be found here: https://github.com/poeschel/mio-pollpri-test

The program sends messages over a TCP socket and checks the received events. We also send a MSG_OOB message. There you can see that the MSG_OOB is in fact received, but does not contain the EPOLLPRI flag, and does not have the priority set to true. Output from the program (only the second message to keep it brief) in this case:

[src/main.rs:43] event = Event {
    token: Token(
        1,
    ),
    readable: true,
    writable: false,
    error: false,
    read_closed: false,
    write_closed: false,
    priority: false,           <<<<<
    aio: false,
    lio: false,
    details: epoll_event {
        events: EPOLLIN,       <<<<<
        u64: 1,
    },
}

With the "horrible hack" posted above, the output changes to:

[src/main.rs:43] event = Event {
    token: Token(
        1,
    ),
    readable: true,
    writable: false,
    error: false,
    read_closed: false,
    write_closed: false,
    priority: true,                   <<<<<
    aio: false,
    lio: false,
    details: epoll_event {
        events: EPOLLIN|EPOLLPRI,     <<<<<
        u64: 1,
    },
}

You can see that the flags contains EPOLLPRI and the priority field is set to true. That likely means MSG_OOB was received only because it also contains the EPOLLIN flag.

As mentioned above, we work with V4L2, and our events do only contain EPOLLPRI. Changing the selector to generally also accept EPOLLPRI events like in our hack, seems like a big breaking change, so we are not quite sure how to proceed.

@Thomasdezeeuw
Copy link
Collaborator

Hello, I am working with @poeschel on this problem. We have created a small test project which can be found here: https://github.com/poeschel/mio-pollpri-test

This program is incorrect. You should get only a single event for the send on line 20. You should drain the readiness, see https://docs.rs/mio/latest/mio/struct.Poll.html#readiness-operations, to get another event.

@poeschel
Copy link
Contributor Author

I created pull-request #1646 that demonstrates the issue a bit better.

@poeschel
Copy link
Contributor Author

poeschel commented Jan 30, 2023

... and I would suggest something like this as a possible solution: poeschel@282edd3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants