-
Notifications
You must be signed in to change notification settings - Fork 724
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
Does deregister clear events already pending delivery? Should it? #219
Comments
You have a chance of receiving the event. I think having |
That would work for |
The best way to do it would require an array scan of buffered events when deregistering tokens that are not the current one being processed. I'm unsure if this is worth the overhead vs. adding a cc @rrichardson |
I like the Handler::tick() alternative more, otherwise you end up with loads of de/register around, and array scanning every time might not be cheap. |
I'm hopping for no |
@dpc that's true for kqueue, but I guess we can extend it to epool too in order to implement this. |
I am currently leaning against adding any overhead in the epoll case. Hoping more people weigh in though. |
Well I'm not sure it's even possible in some sane way. Let's me try to explain...
And when using Slab for tokens, as @dpc already said, you can't just deregister and deallocate and tolerate spurious events, because token might get reused in this loop iteration. So it's kinda ugly. And I believe it should be fixed by mio. In case you can tolerate that and want "raw" performance, there is always an option to use |
So, I haven't hit the issue in question yet, so I need some help trying to understand. For cases where sockets aren't interrelated, there isn't an issue. The EventLoop won't produce any further events with the token. For cases where multiple sockets are interrelated, say a proxy, where if one end closes, you want to close both ends. The issue seems to be that the tokens for both sockets are "released" back to the pool, thus any further notifications using the token will be problematic. Having @tailhook I don't understand why point #3 is a problem. If you temporarily deregister a socket, you aren't releasing the token back into the pool, so there will be no token conflict. |
Ah, okay, I just need to have different deregister code path for temporary and final deregister. And also ignore spurious events. It's not too simple, but may work. |
@carllerche , I'm not sure what do you mean in "Having deregister guarantee that no further events happen w/ the token is not actually enough, " paragraph. The problem is with sockets being interrelated, yes. But the root of the problem is that Because of the fact that that events are delivered in groups, if during processing of one event in the current group the interest in the following events in that group can be removed. This can happen in two cases: with The core proposition is: "mio must guarantee that it will never deliver any event that the Handler is actively waiting for in a given time". |
This might be problematic when using edge triggered events, or not? |
I don't see why. My understanding is: "edge triggered" means that if the condition generating even was deasserted, the event will be still generated. But this issue is about what Handler is expecting. If Handler deregistered from certain events, it should not receive them. |
@dpc My point is, "closing" a socket is also "deregisters" the socket. However, since this entirely happens in the kernel, there is no way for mio to purge any pending events. |
So, either the two options are:
|
It is tempting to use mio as both a state machine and general event management system. I would recommend against this. One reason is that, despite our efforts to the contrary, you might get different behavior on different platforms, since it is the OS kernel that is generating the events. I would recommend in addition to de-registering descriptors on an event, that you also update some internal state and use that state to dictate your actions when handling events. This is the only way to be sure that you'll get consistent performance. tl;dr Changing mio to purge events would be too much effort, both in developer effort and cpu cycles to support a mechanism that shouldn't be used. One should not be using deregister as a means of influencing control flow in their system. |
@rrichardson +1 My opinion is that any registration or de-registration should only take place between calls to |
So the |
If we have a tick() method we can actually remove the event aggregation machinery from KQueue, right? |
protip: if you keep internal state anyway it's better use use edge-triggered mode because that allows to avoid all |
I wonder if it would be possible to write a layer library on top of |
I might attempt writing such a functionality in mio itself. Would you be OK if all the overhead we discuss here was a compile time It's just in mioco spurious events are ruining
So I think it might be worth it to take a tiny overhead (one fast lookup on every reregister and deregister) than complicate your code and risk having software that in certain situations experiences weird hiccups. The feature would be making The benefit of compile time feature is that people experiencing any issues could quickly check if that might be a cause. And those sure that their code handles this conditions just right, can get a pure performance version. |
The `Handler::tick()` method is called at the beginning of each event loop tick. Fixes tokio-rs#219
The `Handler::tick()` method is called at the end of each event loop tick. Fixes tokio-rs#219
The `Handler::tick()` method is called at the end of each event loop tick. Fixes tokio-rs#219
A single event loop tick may contain multiple events for a token. If the connection is reset on the first event, subsequent events will still try to access that token/connection during the event loop tick. The strategy now is to mark a connection as reset and remove them only when the event loop tick is finished. See tokio-rs/mio#219 for more details. Fixes #1
The `Handler::tick()` method is called at the end of each event loop tick. Fixes #219
* Make `select-*` explicitly warn about returning spurious events. It's just to complicated (impossible?) to guarantee never waking up on a spurious event. (see eg. tokio-rs/mio#219) * Introduce `try_write()`/`try_read()`, to be used with `select-*` * Rename and tweak operations on some `EventSource`-s, since this is breaking change anyway. * Bump the version.
* Make `select-*` explicitly warn about returning spurious events. It's just to complicated (impossible?) to guarantee never waking up on a spurious event. (see eg. tokio-rs/mio#219) * Introduce `try_write()`/`try_read()`, to be used with `select-*` * Rename and tweak operations on some `EventSource`-s, since this is breaking change anyway. * Bump the version.
@tailhook how would internal state + edge-triggered avoid any reregister calls? |
@hjr3 you just always listen for reads and writes and keep internal state of whether your socket is still readable or writable. I mean if you want to pause reading, you don't to deregister (or anything actually). When you want to unpause reading, you look at internal state: if the socket was readable, read from the socket until EAGAIN (or TryRead::read returns Ok(None)). If it wasn't, wait until next edge-triggered read event. |
@tailhook do you have an example of this? I thought edge-triggered meant the event loop will automatically deregister our connection when we receive a read/write event. Maybe we can discuss it more on irc. I am hjr3 in the mio channel as well. |
edge + oneshot will disarm the FD after an event is fired. |
Ah, right. Thanks @carllerche |
Let's say I have two event sources registered, both of them fired at the same time and landed in pending events list for current iteration.
While handling the first event, I do
deregister
on the other one. Will I still get it? It seems to me that I will, which is very inconvenient, as it makes hard (impossible?) to safely deregister events other than the one that just fired.A spin of the above case is: What if I do
deregister
and right after usedregister_opt
on different event source, using the same token.Another spinoff is: What if I do
reregister
using different interest.If I am not missing anything, it seems to me that either: the end of each event delivery iteration should have a notification, during which calls like
deregister
andreregister
can be safely used, orderegister
andreregister
should make sure to remove any events that are not to be delivered anymore.The text was updated successfully, but these errors were encountered: