-
Notifications
You must be signed in to change notification settings - Fork 721
Add scheduleCallback APIs to NIOIsolatedEventLoop
#3263
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
Conversation
| @discardableResult | ||
| func _scheduleCallbackIsolatedUnsafeUnchecked( | ||
| at deadline: NIODeadline, | ||
| handler: some NIOScheduledCallbackHandler | ||
| ) throws -> NIOScheduledCallback | ||
|
|
||
| @discardableResult | ||
| func _scheduleCallbackIsolatedUnsafeUnchecked( | ||
| in amount: TimeAmount, | ||
| handler: some NIOScheduledCallbackHandler | ||
| ) throws -> NIOScheduledCallback |
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.
@Lukasa do we need those additional hooks on the EL? What was the reasoning behind adding the _scheduleCallbackIsolatedUnsafeUnchecked?
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.
We needed it because the existing EL hooks require Sendable, and they require a specific type. So it isn't possible to pass a T through them that isn't Sendable, because wrapping it into a NIOLoopBound makes it not a T anymore. In this case, a NIOLoopBound<some (NIOScheduledCallbackHandler & Sendable)> isn't a some (NIOScheduledCallbackHandler & Sendable), so it cannot be passed through there.
Wrapping things in a sufficiently large number of loop bounds can work, but performs poorly, and we don't want to pessimise the performance of the on-loop case. That's what we want to work best.
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.
Great, if I understand you correctly adding the above methods is our intend outcome.
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.
Does this mean, we want to work with our own unsafe transfer method in this PR, so that we don't use NIOLoopBound at all? To work around the preconditions?
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.
Cool, so we do want to use assertions (and therefore the ...UnsafeUnchecked method) rather than the NIOLoopBound which provides a precondition
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.
Oh I think we wrote that at the same time 😄
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.
Yeah, and we should also implement a version that doesn't require this fallback for SelectableEventLoop, EmbeddedEventLoop, and AsyncTestingEventLoop.
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.
Cool, done. 97deac6 Should I leave those changes for a different PR?
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.
Sounds reasonable to me.
fabianfett
left a comment
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 so much for the progress so far and for tackling this issue! @Lukasa can you please also give this an early look?
| @discardableResult | ||
| func _scheduleCallbackIsolatedUnsafeUnchecked( | ||
| at deadline: NIODeadline, | ||
| handler: some NIOScheduledCallbackHandler | ||
| ) throws -> NIOScheduledCallback | ||
|
|
||
| @discardableResult | ||
| func _scheduleCallbackIsolatedUnsafeUnchecked( | ||
| in amount: TimeAmount, | ||
| handler: some NIOScheduledCallbackHandler | ||
| ) throws -> NIOScheduledCallback |
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.
We needed it because the existing EL hooks require Sendable, and they require a specific type. So it isn't possible to pass a T through them that isn't Sendable, because wrapping it into a NIOLoopBound makes it not a T anymore. In this case, a NIOLoopBound<some (NIOScheduledCallbackHandler & Sendable)> isn't a some (NIOScheduledCallbackHandler & Sendable), so it cannot be passed through there.
Wrapping things in a sufficiently large number of loop bounds can work, but performs poorly, and we don't want to pessimise the performance of the on-loop case. That's what we want to work best.
|
Okay so I think this is ready for a proper review |
| } | ||
|
|
||
| @usableFromInline | ||
| struct UnsafeUncheckedScheduledCallbackHandlerWrapper<Handler: NIOScheduledCallbackHandler>: |
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.
I don't think this needs to be unsafe. Instead, let's implement this in terms of NIOLoopBound. That way we preserve the logical semantics, and avoid an @unchecked Sendable.
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.
Didn't we decide on using assertions rather than preconditions a few messages above?
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.
In the unchecked fast path, yes. But the slower fallback is just that: slower. As a result, we can safely re-use things we already have, and avoid proliferating @unchecked Sendable.
In general I have a plan to increasingly remove the @unchecked Sendables in NIO because there are far too many, and they can be very damaging. So wherever we can use an existing spelling for this, I'd prefer we did.
fabianfett
left a comment
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.
Lukasa
left a comment
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.
Very nice patch @ptoffy, thank you so much! ✨
Fixes #3262 by adding the missing APIs.
Motivation:
As explained by the issue linked above, having a non-
Sendable-requiring variant of the newscheduleCallbackAPIs onNIOIsolatedEventLoopcan be useful since we're not always dealing withSendabletypes.Modifications:
This adds the required
scheduleCallbackAPIs toNIOIsolatedEventLoopby wrapping the non-SendableNIOScheduleCallbackHandlerin aNIOLoopBound-based handler.Result:
The two
scheduleCallbacks can be used onNIOIsolatedEventLooptoo.