-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[Concurrency]: call AsyncStream's onCancel at most once #83190
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -338,6 +338,10 @@ public struct AsyncStream<Element> { | |
) { | ||
let storage: _AsyncStreamCriticalStorage<Optional<() async -> Element?>> | ||
= .create(produce) | ||
|
||
let cancelStorage: _AsyncStreamCriticalStorage<(() -> Void)?>? | ||
= if let onCancel { .create(onCancel) } else { nil } | ||
|
||
context = _Context { | ||
return await withTaskCancellationHandler { | ||
guard let result = await storage.value?() else { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i think there might also be a 'philosophical' question here about what the appropriate behavior is if we know that the cancel handler has been invoked during a suspension of the |
||
|
@@ -347,6 +351,7 @@ public struct AsyncStream<Element> { | |
return result | ||
} onCancel: { | ||
storage.value = nil | ||
let onCancel = cancelStorage?.access { $0.take() } | ||
onCancel?() | ||
} | ||
} | ||
|
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'm not sure introducing another lock is the ideal approach, but it seems at least serviceable. it wasn't immediately obvious to me if
_AsyncStreamCriticalStorage
supports a fully generic payload, or if it's supposed to contain only a closure (or closure-sized generic parameter?) per this comment. also i tried changing to useMutex
directly, but could not get the tests to successfully build, so unsure if that approach would be an option.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'd try to make a
_Storage
struct and make it have onCancel as well as the other state in there; so we don't have to have separate locks like this