-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[SE-0304] Align Task API implementation with the fourth revision of the proposal #38306
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
[SE-0304] Align Task API implementation with the fourth revision of the proposal #38306
Conversation
Do this as a staged change to the ABI, introducing an underscored `@usableFromInline` implementation to the ABI that we can rely on later, and an `@_alwaysEmitIntoClient` version we can inline now.
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.
Hope an unsolicited review is OK
78e4dad
to
c6be200
Compare
c6be200
to
59d1e61
Compare
@swift-ci please test |
|
||
@available(SwiftStdlib 5.5, *) | ||
@main struct Main { | ||
static let pause = 500_000_000 // 500ms |
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.
it might also be good to test the 0 case of a pause
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 point, I'm adding it in a subsequent commit.
} | ||
} onCancel: { | ||
let continuationWord = continuationPtr.pointee | ||
if UInt(continuationWord) != 0 { |
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.
is this safe from here on out if another thread cancels just after the checkCancellation
at line 84?
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.
So, there's an existing race in withTaskCancellationHandler
that also gets replicated here. When we address that (@ktoso was looking into it), this will also be fixed.
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'll get to it this week. I think we'll end up having to "check again" after having stored a cancellation record basically.
try checkCancellation() | ||
|
||
// Allocate storage for the flag word and continuation. | ||
let wordPtr = UnsafeMutablePointer<Builtin.Word>.allocate(capacity: 2) |
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.
this word does not escape the context of this function right? it might be interesting to actually use a stack allocation instead of heap allocating it.
else wise if it does escape then this probably should be ref counted right?
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.
It does escape the context of this function: when the task is cancelled, the timed "wake" task has yet to be scheduled, and needs to check whether it finished first or not. In the case where it gets called but didn't finish first, it handles the deallocation.
No need for reference counting; the deallocation points are well-defined.
The prior implementation of `Task.sleep()` effectively had two different atomic words to capture the state, which could lead to cases where cancelling before a sleep operation started would fail to throw `CancellationError`. Reimplement the logic for the cancellable sleep with a more traditional lock-free approach by packing all of the state information into a single word, where we always load, figure out what to do, then compare-and-swap.
@swift-ci please test |
@swift-ci please test Windows |
Specific changes are:
async
operations toaddTask
TaskPriority.default
toTaskPriority.medium
Task.yield()
toTask.suspend()
waitForAll()
Task.sleep(nanoseconds:)
All changes with the exception of
Task.sleep(nanoseconds:)
are implemented in an ABI-neutral manner.Task.sleep(nanoseconds:)
is ABI-additive; it's too much code to want to inline.Implements rdar://80339563