-
Notifications
You must be signed in to change notification settings - Fork 68
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
m(windows): Reimplement Wepoll in Rust #88
Conversation
I think this is stable enough for review now; the tests aren't catching any bugs that I can see (although the |
Implement polling for Windows Reimplement wepoll in Rust Fix immediately obvious bugs Fix AFD event translation Fix MSRV build errors Make sure to unlock packets after retrieval Lock sources list with rwlock instead of mutex
90e5013
to
6b668af
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! I have not reviewed the details regarding the Windows API, but at first glance, this looks great.
Also, we may want to test some downstream crates before merging/releasing this patch because such a rewrite may cause subtle differences in behavior. (in the similar way that our CI tests async-io)
I just ran a small "crater test" on a few crates that have
All of the tests seem to pass (or at least the ones that weren't already failing on Windows). I think we're fine in terms of potentially undefined behavior. Edit: I included this excerpt in their
|
unsafe impl<T: Completion> CompletionHandle for Pin<Arc<T>> { | ||
type Completion = T; | ||
|
||
fn get(&self) -> Pin<&Self::Completion> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is the pointer that this function returns pinned?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The pinning ensures that the overlapped object isn't moved while it's involved in an operation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how could it be moved when it is behind an &
reference?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While it's being used in the overlapped operation, there is no reference (or at least, none that the borrow checker is aware of). As a safeguard against undefined behavior, this ensures that it isn't invalidated during the operation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hm, seems a bit brittle, but I'll go with it for now.
Thanks for the work btw. Looks impressive. |
Thanks for the review! I know this is a monster PR, so I appreciate you taking the time to sit down and look through it all. I'll merge once the CI passes. |
It might be a good idea to do another downstream test, otherwise this looks ok. I think it is appropriate to squash-merge this when done. The possible brittleness of
Can/do we enforce that? |
A Lines 491 to 505 in e85331c
|
Reimplements the C-based wepoll backend in Rust, using some handwritten code. This PR also implements bindings to the I/O Completion Ports and \Device\Afd APIs. For more information on the latter, see my blog post on the subject: https://notgull.github.io/device-afd/ Note that the IOCP API is wrapped using a `Pin`-oriented "CompletionHandle" system that is relatively brittle. This should be replaced with a better model when one becomes available.
Making sure that this works on Windows after #88
Thus far,
wepoll
has served us well in terms of polling on Windows. However, at this stage, it's time to migrate to our own home-rolled implementation. There is at least one critical soundness bug that stems from our usage ofwepoll
(#85), and it would be significantly easier to compilepolling
(as well as all of its dependents) if we purged our only C dependency. In addition, there are some issues that we can only solve if we move away fromwepoll
(smol-rs/async-io#17, smol-rs/async-io#25, #82).The new strategy is similar to what
wepoll
currently does, except (hopefully) more robust. The core consists of using an I/O Completion Port as the core of the system, and then using the undocumented Auxillary Function Driver to deliver completion packets whenever a socket is considered "ready". There is a state object associated with each socket that contains the events currently being polled, the in-flight events associated with the socket, and whether the socket state is queued for deletion.The differences between this implementation and
wepoll
includes:HashMap
.ConcurrentQueue
is used to hold pending socket updates, rather than a naive queue implementation. This queue has a capacity of 1024 elements and every update is run run the queue is full. In contrast,wepoll
's queue is unbounded.Pin
guarantees, in order to prevent state captured by the I/O completion port from being moved.epoll_event
intermediary, we directly convert completion packets toEvent
s.Poller
through a designated wakeup packet.AtomicBool
instead of an atomic number.Closes #22 and closes #85. Supersedes #76.