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

Event Re-Registration #45

Closed
rrichardson opened this issue Nov 11, 2014 · 6 comments
Closed

Event Re-Registration #45

rrichardson opened this issue Nov 11, 2014 · 6 comments

Comments

@rrichardson
Copy link
Contributor

There are a couple fundamental flaws in using Edge Triggered without One Shot.

Data Loss due to non notification
The first and most major is that if the read() in response to a read-event doesn't consume all of the data from the socket's buffer, it will never be notified about data again, which means the read-event won't be called again and the data will remain forever alone.

Starvation
The model of needing to consume all data out of a socket can lead to starvation of other sockets if there is an extreme amount of data being sent into that socket. A better model would be to consume a small amount of data per each socket, in turn, and go back to epoll_wait.

There are two solutions to this:

Level Triggered
This is easier for people to get right, as you'll always be notified if data is present in the case of read, or the socket is ready in case of write. The downside is it can be spammy, you don't need to be constantly notified of Writable events if you don't care about writing. A web server is a great example, it only needs to write after it receives a request. The solution is, obviously, to allow an application to un-register its interest in writing when it doesn't care about writing.

Edge Triggered with One Shot
This is the recommended approach. This would also require frequent re-registration, but epol_ctl is a very cheap syscall (cheaper than read() returning EAGAIN)
This would require every read and writer to re-register their interest in reading and writing after every epoll_wait call that returns events for that FD.
This solves both of the above problems. Epoll_wait will return fds who have data waiting regardless of whether it has been resting a while or has recently arrived.

IMO, the best approach is to let the user specify if they want edge triggered vs level triggered. But regardless of that model, there should definitely be a reregister function.

@carllerche
Copy link
Member

I accept. How does level triggered & reregistration work on other platforms (not counting windows)?

@carllerche carllerche mentioned this issue Nov 11, 2014
4 tasks
@rrichardson
Copy link
Contributor Author

IIRC, kqueue is edge triggered only, but it does support one-shot.

@carllerche
Copy link
Member

Quick google search:

Yeah that's right. I discovered that too while testing kqueue. Without
EV_CLEAR, kevent acts as level-triggered (it always returns as long as a
condition holds, socket readable/writeable etc). Setting EV_CLEAR causes
kevent to act as edge-triggered (it returns once when state changes and will
block on second call until state changes again).

So it seems possible to implement on those systems. What API do you have in mind? Add an option to EventLoopConfig or something else?

Also, how would a re-registration API differ from the existing register fn?

@rrichardson
Copy link
Contributor Author

Two ways:

  1. The current register doesn't take events, it just registers for everything.
  2. EPOLL_CTL_ADD vs EPOLL_CTL_MOD

I'd allow register to selectively specify interest (maybe supply an IoEventKInd of IOEVENTALL as a convenience for people)
and also ad reregister which requires people to specify the events in which they're interested.

@carllerche
Copy link
Member

Re 1), register should take the interests, see #33. 2 makes sense, I had unloaded epoll from my brain :P

@carllerche
Copy link
Member

Resolved by 0122914

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

No branches or pull requests

2 participants