Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Add inverse of preconditionInEventLoop() and ability to add messages to the assertion #1508

Merged
merged 8 commits into from
May 11, 2020
Merged

Add inverse of preconditionInEventLoop() and ability to add messages to the assertion #1508

merged 8 commits into from
May 11, 2020

Conversation

gwynne
Copy link
Contributor

@gwynne gwynne commented May 6, 2020

Add preconditionNotInEventLoop(_:file:line:) and assertNotInEventLoop(_:file:line:), and add optional message parameter to the existing counterparts.

WARNING: There are no tests for the existing or new precondition APIs, as unit tests can not test crash conditions and the integration tests currently can not build all of NIO when testing crashes. An issue will be filed to track addressing this shortcoming.

Motivation:

  1. It is valuable to be able to provide additional context for any kind of assertion failure, such as obvious points of API misuse or when the purpose of the assertion itself is unclear. The explainer message provided on precondition failure in EventLoopFuture.wait() is an ideal example.

  2. As it is useful to have a precondition to assert that calling code is on the given EventLoop, it is also useful to assert that calling code is not on that EventLoop. Precedent is provided by the dispatchPrecondition() API.

Modifications:

  • Added a distinct overload of preconditionInEventLoop() that accepts a message @autoclosure parameter in the same fashion as does Swift.precondition(_:file:line:). The overload's implementation calls that very function with the appropriate inputs, including the forwarded message (if any). The implementation of the original version now calls through to the new one with an empty message, providing 100% source compatibility.
  • Added the same new parameter to assertInEventLoop(). Didn't bother with a forwarder, as the method is not specified on the EventLoop protocol; just gave the new param a default value.
  • Rewrote the comments of all aforementioned methods to be both more grammatical and more technically precise.
  • Add the two new inverse methods to EventLoop, providing the precondition form as a protocol requirement and the assertion form only as an extension method, to match their counterparts.
  • Provide defaulted implementations of the new methods as appropriate to their defined behaviors. The new methods also accept message autoclosure inputs but, being newly added, default the argument rather than adding forwarders.
  • Finally, replaced various uses of precondition(!eventLoop.inEventLoop) and assert(!eventLoop.inEventLoop) by EventLoopFuture and NIOHTTP1TestServer with eventLoop.preconditionNotInEventLoop() and eventLoop.assertNotInEventLoop() respectively.

Result:

  • It is now possible to optionally provide explanatory messages to be included when "in/not in event loop" preconditions fail, as with any other precondition failure, matching the behavior of the Swift.precondition() API.
  • It is now possible to canonically assert that a given execution path is not executing in the thread context belonging to a given event loop. Improves parity with dispatchPrecondition(), allows replacing direct access to EventLoop.inEventLoop with direct statements of intent, and enables overriding the assertion behaviors on a per-loop basis (such as the use of dispatchPrecondition() by NIOTSEventLoop, not shown in this PR of course),

gwynne added 4 commits May 6, 2020 08:06
Motivation:

It is valuable to be able to provide additional context for any kind of assertion failure, such as obvious points of API misuse or when the purpose of the assertion itself is unclear.

Modifications:

Added an overload of preconditionInEventLoop() that accepts a message autoclosure parameter in the same fashion as `Swift.precondition(_:file:line:)`. Default the implementation of the original version to calling the new one with an empty message. Add defaulted implementation of the new version which forwards the message closure to precondition(). Add the new message parameter directly to assertInEventLoop() without a forwarder since it is not a customization point.

Result:

It is now possible to optionally provide explanatory messages to be included when the "in event loop" precondition fails, as with any other precondition.
…or clarity.

Motivation:

The existing comments were grammatically a bit awkward.

Modifications:

Changed the comments.

Result:

The documentation comments are more grammatically correct and technically precise.
…o EventLoop.

Motivation:

As it is useful to have a precondition to assert that calling code *is* on the given EventLoop, it is also useful to assert that calling code is *not* on it.

Modifications:

Add two new methods to EventLoop, one of them as a protocol method, both with default implementations.

Result:

It is now possible to canonically assert that a given execution path is *not* executing on a given event loop (including providing an explanatory message, as with the earlier changes to the counterpart methods). This provides better parity with dispatchPrecondition() and enables replacing direct access to `EventLoop.inEventLoop` with a direct statement of intent providing guaranteed semantics.
…propriate locations.

Motivation:

This is the purpose for which the new methods were intended: To replace handwritten conditions with direct statements of assertion intent.

Modifications:

Replaced various uses of precondition(!eventLoop.inEventLoop) and similar assert()s with the respective *notInEventLoop methods. In the case of the usage in EventLoopFuture.wait(), ensure the explainer message is provided on precondition failure.

Result:

The modified code is clearer, explicitly declares intent, can benefit from customizations provided by individual event loop types (such as the use of dispatchPrecondition() in NIOTSEventLoop), and can be more easily refactored.
@gwynne
Copy link
Contributor Author

gwynne commented May 6, 2020

Filed #1509 to track crash-detecting integration tests that cover all of NIO's codebase.

@gwynne
Copy link
Contributor Author

gwynne commented May 6, 2020

The failure of the API breakage test is expected given the new APIs added and the source-compatible change of assertInEventLoop()'s signature, I think?

Copy link
Contributor

@Lukasa Lukasa left a comment

Choose a reason for hiding this comment

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

Generally looks good. Please also file a NIOTS issue to adopt these APIs in terms of dispatchPrecondition

@gwynne
Copy link
Contributor Author

gwynne commented May 6, 2020

Generally looks good. Please also file a NIOTS issue to adopt these APIs in terms of dispatchPrecondition

A PR addressing the implementation for NIOTS is in progress.

@gwynne
Copy link
Contributor Author

gwynne commented May 7, 2020

First draft of changes for NIOTS is up. Needs significant additional work.

@Lukasa Lukasa added the 🆕 semver/minor Adds new public API. label May 7, 2020
@Lukasa Lukasa added this to the 2.17.0 milestone May 7, 2020
Copy link
Contributor

@Lukasa Lukasa left a comment

Choose a reason for hiding this comment

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

Ok, I'm definitely happy with the shape of this. We can work through the NIOTS issue separately.

Lukasa pushed a commit to apple/swift-nio-transport-services that referenced this pull request May 7, 2020
Motivation:

See apple/swift-nio#1508 for rationale

Modifications:

Provides implementations of `preconditionInEventLoop(_:file:line:)` and `preconditionNotInEventLoop(_:file:line:)`.

Result:

NIOTSEventLoop will now use dispatchPrecondition(condition:) for the in/not in preconditions instead of relying on the default implementation, yielding improved correctness.
Copy link
Member

@weissi weissi left a comment

Choose a reason for hiding this comment

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

Thank you, looks awesome. Small change request for the existing functions

…both existing and new precondition methods on EventLoop, including pulling the new overloads entirely. Add some missing @inlinable attributes while at it. Revert EventLoopFuture.wait() to using precondition() directly to ensure its explainer message is shown.
Copy link
Member

@weissi weissi left a comment

Choose a reason for hiding this comment

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

Looks great, thank you!

Lukasa pushed a commit to apple/swift-nio-transport-services that referenced this pull request May 7, 2020
… removing the message parameter from the precondition assertion methods entirely. Added a couple of missing @inlinables to match the declarations now present over there as well. (#85)
@Lukasa
Copy link
Contributor

Lukasa commented May 11, 2020

Cool, I think we think the API breakage checker is wrong for known reasons, so I'm going to merge this.

@Lukasa Lukasa merged commit add3e40 into apple:master May 11, 2020
pull bot pushed a commit to scope-demo/swift-nio that referenced this pull request May 11, 2020
…s to the assertion (apple#1508)

Motivation:

It is valuable to be able to provide additional context for any kind of assertion failure, such as obvious points of API misuse or when the purpose of the assertion itself is unclear.

Modifications:

Added an overload of preconditionInEventLoop() that accepts a message autoclosure parameter in the same fashion as `Swift.precondition(_:file:line:)`. Default the implementation of the original version to calling the new one with an empty message. Add defaulted implementation of the new version which forwards the message closure to precondition(). Add the new message parameter directly to assertInEventLoop() without a forwarder since it is not a customization point.

Result:

It is now possible to optionally provide explanatory messages to be included when the "in event loop" precondition fails, as with any other precondition.
@gwynne gwynne deleted the precondition-not-in-eventloop branch May 16, 2020 15:13
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
🆕 semver/minor Adds new public API.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants