Motivation:
As outlined in #1761, io_uring is a new async I/O facility on Linux.
This commit includes a second stab at adding this to SwiftNIO.
Modifications:
Added Uring Selector implementation.
Added liburing support shims.
Disabled one assert that trips during normal usage likely due to async nature of poll updates, for discussion
Added shared kernel sqpoll ring support (can be run with normal user privs in 5.13)
Support for both single shot polls (should work all the way back to 5.1 kernels, needs testing) and multishot streaming polls and modifications for polls (scheduled due in 5.13) for slightly better performance (and better impedance match to SwiftNIO usage)
Added extensive debug logs which can be enabled with -D compiler flags (should likely be removed when bringup and testing is complete)
Adjusted tests.
Added documentation.
Result:
Basic liburing support is in place.
Co-authored-by: Johannes Weiss <johannesweiss@apple.com>
Motivation:
Right now all tasks scheduled onto an event loop from a different loop
wake up the underlying selector by writing to an eventfd. This is a
fairly inefficient way to handle things: it incurs a lot of syscall
traffic unnecessarily.
Given that we currently protect the pending tasks queue with a big dumb
lock, we can safely keep track of whether we're going to dequeue this
task. If we are, we don't need to wake the selector.
Modifications:
- Keep track of whether we're de-queueing tasks or not.
- Arrange to wake the selector only once.
Result:
Cheaper task enqueueing on hot loops.
Motivation:
We and the OSes only support `CInt` as file descriptors. For some reason
we had interfaces that took `Int`s as fds which requires frequent
casting around. This is unnecessary.
Modifications:
- make fds `CInt` (internally)
- clean up some `Int32` as `CInt` use
Result:
cleaner code, less casting
Motivation:
Instead of manual shifting / masking we can write the whole registration
ID code normally in Swift.
Modifications:
Refactored RegistrationID to use Swift instead of shifting / masking.
Result:
Nicer code.
Motivation:
Currently the selector implementation just discards all pending events from the kernel when a deregistration
has occurred during the event loop tick. This has been needed to not fail the test testWeDoNotDeliverEventsForPreviouslyClosedChannels.
A cleanup case has been around for a while at: https://github.com/apple/swift-nio/issues/381
And when discussing this in https://github.com/apple/swift-nio/pull/1788 (to solve https://github.com/apple/swift-nio/issues/1761)
we came to an agreement that the solution with tagging registrations on the backend would not suit only io_uring,
but also solve the issue robustly for kqueue and epoll.
Modification:
Added sequenceIdentifier to the Registration and add support for it throughout.
Mask in sequence identifier into user data in both kqueue and epoll.
In kqueue, we just store the sequence identifier in the udata field (to support 32-bit properly).
In epoll, where we know we have 64-bits, we mask it in together with fd.
Removed all references to the old workaround from #381.
Result:
- New solution that doesn't need to discard all events when deregistrations are done during the event loop tick.
- fixes#381
Motivation:
Currently all backends are platform-conditional in the `Selector` code, making it
harder to read and difficult to extend for future new backend implementations.
By splitting the `Selector` into a generic part and per-backend platform implementation
it is easier to add additional backends in the future.
Modifications:
Split Selector into `SelectorGeneric`, `SelectorEpoll` and `SelectorKqueue`.
Add a _SelectorBackendProtocol that should be implemented by actual backends.
Fixed tests.
Result:
- Easier to read code
- Makes it easier to add new backends
Co-authored-by: Cory Benfield <lukasa@apple.com>
Co-authored-by: Johannes Weiss <johannesweiss@apple.com>