-
Notifications
You must be signed in to change notification settings - Fork 735
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
deregister() sometimes fails with "No such file or directory" on MacOS #911
Comments
The only way I can think of If I'm correct https://github.com/Genymobile/gnirehtet/blob/2bf8a3cfbe2168031897b8f917c088fe6d47710c/relay-rust/src/relay/tcp_connection.rs#L788 is the line that causes this. Could you add an assertion/check that ensure that |
Thank you for your answer.
I will ask to the user who can reproduce the problem. But with the provided logs (with this patch Genymobile/gnirehtet#136 (comment)), we already see that |
I encountered a similar problem with FreeBSD. //
// FreeBSD
//
$ uname -a
FreeBSD freebsd-11-1 11.2-RELEASE-p9 FreeBSD 11.2-RELEASE-p9 #0: Tue Feb 5 15:30:36 UTC 2019 root@amd64-builder.daemonology.net:/usr/obj/usr/src/sys/GENERIC amd64
$ cargo new miotest
$ cd miotest/
$ echo 'mio = "0.6.16"' >> Cargo.toml
$ vi src/main.rs // See below code
$ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.03s
Running `target/debug/miotest`
thread 'main' panicked at 'This expression fails on FreeBSD, but doesn't on Linux: Os { code: 2, kind: NotFound, message: "No such file or directory" }', src/libcore/result.rs:1009:5
note: Run with `RUST_BACKTRACE=1` for a backtrace.
//
// Debian
//
$ uname -a
Linux instance-1 4.9.0-8-amd64 #1 SMP Debian 4.9.130-2 (2018-10-27) x86_64 GNU/Linux
// .. abbrev ..
$ cargo run
Succeeded // src/main.rs: This code is copied from https://docs.rs/mio/0.6.16/mio/#example.
use mio::net::{TcpListener, TcpStream};
use mio::*;
const SERVER: Token = Token(0);
const CLIENT: Token = Token(1);
fn main() {
let addr = "127.0.0.1:13265".parse().unwrap();
let server = TcpListener::bind(&addr).unwrap();
let poll = Poll::new().unwrap();
poll.register(&server, SERVER, Ready::readable(), PollOpt::edge())
.unwrap();
let sock = TcpStream::connect(&addr).unwrap();
// NOTE(sile): `PollOpt::oneshot()` is added by me.
poll.register(
&sock,
CLIENT,
Ready::readable(),
PollOpt::edge() | PollOpt::oneshot(),
)
.unwrap();
let mut events = Events::with_capacity(1024);
loop {
poll.poll(&mut events, None).unwrap();
for event in events.iter() {
match event.token() {
SERVER => {
let _ = server.accept();
}
CLIENT => {
// NOTE(sile): The following two lines are added by me.
poll.deregister(&sock)
.expect("This expression fails on FreeBSD, but doesn't on Linux");
println!("Succeeded");
return;
}
_ => unreachable!(),
}
}
}
} |
This looks like a bug in how mio handles oneshot on kqueue-based systems: With kqueue there are only two possible states for a kevent: enabled or disabled. But mio seems to be treating Does mio even allow multiple threads to poll the same file descriptor at the same time? If not, then |
@asomers I'm not exactly following your proposal. |
I'm saying that since
|
Unfortunately, things will get more complicated as the windows side of things is reworked. I'd like to switch the windows impl to something like: https://github.com/piscisaureus/wepoll The downside is this strategy only supports oneshot. |
Searching around, I also found: https://github.com/jiixyj/epoll-shim/blob/master/src/epoll.c |
That epoll-shim looks awfully heavyweight, and it doesn't even handle |
I think the general strategy is to use some of the user data associated with the FD to track enough state to map the epoll API. We should be able to do this as well? |
@asomers I haven't looked in detail, what looks heavyweight? |
That whole file you just linked. It looks like it's trying to emulate the epoll C API on kqueue-based systems. |
@asomers it also sounds like the problem stems from using It already is not possible to move a FD between |
That would be another option. But are there any other legitimate use cases for using |
yes, in fact during shutdown sequence you may very well want to do that
since you don't want events from the socket but you don't want to close it
since it causes the other side to see e.g. pipe broken ... Other case is
when you deregister while draining the socket and re-register to make sure
you don't get spurious events. At least, I have enough code doing this kind
of stuff based on runing MIO under heavy load over lots of threads ...
…On Wed, Feb 20, 2019 at 10:20 AM Alan Somers ***@***.***> wrote:
That would be another option. But are there any other legitimate use cases
for using deregister? Does anybody ever decide to ignore a socket without
closing it?
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#911 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/ABo0CwKUI_DODxGOkq2wbh-LM_0G_u0Zks5vPZHWgaJpZM4aPVMn>
.
|
@asomers @przygienda well, ideally we could do something like remove We probably need to make a list of the various inconsistencies across platforms and see how we can unify. |
So, That said, the biggest problem with using oneshot as the portable strategy is that it adds additional |
I just tried this with mio_st and it worked, I'll try to figure what is different on mio. |
So mio_st actually cheats a bit and simply ignores |
Several users reported this error on MacOS.
Today, I got more logs (see discussion from Genymobile/gnirehtet#136 (comment)) in which
poll.register()
returns aToken(3)
, but passing this token topoll.deregister()
fails withNo such file or directory
.This happens only on MacOS (apparently), so I guess it is related to the kqueue backend.
The text was updated successfully, but these errors were encountered: