8000 Add `scheduleCallback` APIs to `NIOIsolatedEventLoop` by ptoffy · Pull Request #3263 · apple/swift-nio · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

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

Open
wants to merge 10 commits into
base: main
Choose a base branch
from

Conversation

ptoffy
Copy link
@ptoffy ptoffy commented Jun 4, 2025

Fixes #3262 by adding the missing APIs.

Motivation:

As explained by the issue linked above, having a non-Sendable-requiring variant of the new scheduleCallback APIs on NIOIsolatedEventLoop can be useful since we're not always dealing with Sendable types.

Modifications:

This adds the required scheduleCallback APIs to NIOIsolatedEventLoop by wrapping the non-Sendable NIOScheduleCallbackHandler in a NIOLoopBound-based handler.

Result:

The two scheduleCallbacks can be used on NIOIsolatedEventLoop too.

@fabianfett fabianfett requested a review from Lukasa June 4, 2025 15:50
Comment on lines 462 to 472
@discardableResult
func _scheduleCallbackIsolatedUnsafeUnchecked(
at deadline: NIODeadline,
handler: some NIOScheduledCallbackHandler
) throws -> NIOScheduledCallback

@discardableResult
func _scheduleCallbackIsolatedUnsafeUnchecked(
in amount: TimeAmount,
handler: some NIOScheduledCallbackHandler
) throws -> NIOScheduledCallback
Copy link
Member

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?

Copy link
Contributor

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.

Copy link
Member

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.

Copy link
Member

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?

Copy link
Author

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

Copy link
Author

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 😄

Copy link
Contributor

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.

Copy link
Author

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?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds reasonable to me.

Copy link
Member
@fabianfett fabianfett left a 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?

@Lukasa Lukasa added the 🆕 semver/minor Adds new public API. label Jun 5, 2025
Comment on lines 462 to 472
@discardableResult
func _scheduleCallbackIsolatedUnsafeUnchecked(
at deadline: NIODeadline,
handler: some NIOScheduledCallbackHandler
) throws -> NIOScheduledCallback

@discardableResult
func _scheduleCallbackIsolatedUnsafeUnchecked(
in amount: TimeAmount,
handler: some NIOScheduledCallbackHandler
) throws -> NIOScheduledCallback
Copy link
Contributor

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.

@ptoffy ptoffy marked this pull request as ready for review June 5, 2025 15:06
@ptoffy
Copy link
Author
ptoffy commented Jun 5, 2025

Okay so I think this is ready for a proper review

@ptoffy ptoffy requested review from Lukasa and fabianfett June 5, 2025 15:20
@@ -170,3 +170,26 @@ extension EventLoop {
}
}
}

@usableFromInline
struct UnsafeUncheckedScheduledCallbackHandlerWrapper<Handler: NIOScheduledCallbackHandler>:
Copy link
Contributor

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.

Copy link
Author

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?

Copy link
Contributor

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.

@ptoffy ptoffy requested a review from Lukasa June 13, 2025 17:05
Copy link
Member
@fabianfett fabianfett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ptoffy thanks for this PR. I'll wait for @Lukasa final feedback before we can merge.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🆕 semver/minor Adds new public API.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

NIOIsolatedEventLoop does not offer fast timer API
3 participants
0