Skip to content

Commit d6ce46c

Browse files
ktosomeg-gupta
authored andcommitted
[Concurrency] Fix missing inherit executor on withTaskCancellationHandler (swiftlang#62546)
1 parent 7d9f25f commit d6ce46c

File tree

4 files changed

+88
-2
lines changed

4 files changed

+88
-2
lines changed

stdlib/public/BackDeployConcurrency/TaskCancellation.swift

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,19 @@ import Swift
2626
///
2727
/// Doesn't check for cancellation, and always executes the passed `operation`.
2828
///
29-
/// This function returns immediately and never suspends.
29+
/// The `operation` executes on the calling execution context and does not suspend by itself,
30+
/// unless the code contained within the closure does. If cancellation occurs while the
31+
/// operation is running, the cancellation `handler` will execute *concurrently* with the `operation`.
32+
///
33+
/// ### Already cancelled tasks
34+
/// When `withTaskCancellationHandler` is used in a `Task` that has already been cancelled,
35+
/// the `onCancel` cancellation ``handler`` will be executed immediately before operation gets
36+
/// to execute. This allows the cancellation handler to set some external "cancelled" flag that the
37+
/// operation may be *atomically* checking for in order to avoid performing any actual work once
38+
/// the operation gets to run.
39+
@_unsafeInheritExecutor // the operation runs on the same executor as we start out with
3040
@available(SwiftStdlib 5.1, *)
41+
@_backDeploy(before: SwiftStdlib 5.8)
3142
public func withTaskCancellationHandler<T>(
3243
operation: () async throws -> T,
3344
onCancel handler: @Sendable () -> Void
@@ -92,10 +103,12 @@ public struct CancellationError: Error {
92103
public init() {}
93104
}
94105

106+
@usableFromInline
95107
@available(SwiftStdlib 5.1, *)
96108
@_silgen_name("swift_task_addCancellationHandler")
97109
func _taskAddCancellationHandler(handler: () -> Void) -> UnsafeRawPointer /*CancellationNotificationStatusRecord*/
98110

111+
@usableFromInline
99112
@available(SwiftStdlib 5.1, *)
100113
@_silgen_name("swift_task_removeCancellationHandler")
101114
func _taskRemoveCancellationHandler(

stdlib/public/Concurrency/TaskCancellation.swift

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,19 @@ import Swift
2626
///
2727
/// Doesn't check for cancellation, and always executes the passed `operation`.
2828
///
29-
/// This function returns immediately and never suspends.
29+
/// The `operation` executes on the calling execution context and does not suspend by itself,
30+
/// unless the code contained within the closure does. If cancellation occurs while the
31+
/// operation is running, the cancellation `handler` will execute *concurrently* with the `operation`.
32+
///
33+
/// ### Already cancelled tasks
34+
/// When `withTaskCancellationHandler` is used in a `Task` that has already been cancelled,
35+
/// the `onCancel` cancellation ``handler`` will be executed immediately before operation gets
36+
/// to execute. This allows the cancellation handler to set some external "cancelled" flag that the
37+
/// operation may be *atomically* checking for in order to avoid performing any actual work once
38+
/// the operation gets to run.
39+
@_unsafeInheritExecutor // the operation runs on the same executor as we start out with
3040
@available(SwiftStdlib 5.1, *)
41+
@_backDeploy(before: SwiftStdlib 5.8)
3142
public func withTaskCancellationHandler<T>(
3243
operation: () async throws -> T,
3344
onCancel handler: @Sendable () -> Void
@@ -92,10 +103,12 @@ public struct CancellationError: Error {
92103
public init() {}
93104
}
94105

106+
@usableFromInline
95107
@available(SwiftStdlib 5.1, *)
96108
@_silgen_name("swift_task_addCancellationHandler")
97109
func _taskAddCancellationHandler(handler: () -> Void) -> UnsafeRawPointer /*CancellationNotificationStatusRecord*/
98110

111+
@usableFromInline
99112
@available(SwiftStdlib 5.1, *)
100113
@_silgen_name("swift_task_removeCancellationHandler")
101114
func _taskRemoveCancellationHandler(
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// RUN: %target-run-simple-swift( -Xfrontend -disable-availability-checking %import-libdispatch -parse-as-library) | %FileCheck %s --dump-input=always
2+
3+
// REQUIRES: executable_test
4+
// REQUIRES: concurrency
5+
// REQUIRES: libdispatch
6+
7+
// rdar://76038845
8+
// REQUIRES: concurrency_runtime
9+
10+
import Dispatch
11+
12+
@available(SwiftStdlib 5.1, *)
13+
func test_detach_cancel_taskGroup() async {
14+
print(#function) // CHECK: test_detach_cancel_taskGroup
15+
16+
await withTaskGroup(of: Void.self) { group in
17+
group.cancelAll() // immediately cancel the group
18+
print("group.cancel()") // CHECK: group.cancel()
19+
20+
group.addTask {
21+
// immediately cancelled child task...
22+
await withTaskCancellationHandler {
23+
print("child: operation, was cancelled: \(Task.isCancelled)")
24+
} onCancel: {
25+
print("child: onCancel, was cancelled: \(Task.isCancelled)")
26+
}
27+
}
28+
// CHECK: child: onCancel, was cancelled: true
29+
// CHECK: child: operation, was cancelled: true
30+
}
31+
32+
print("done") // CHECK: done
33+
}
34+
35+
@available(SwiftStdlib 5.1, *)
36+
@main struct Main {
37+
static func main() async {
38+
await test_detach_cancel_taskGroup()
39+
}
40+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -emit-module -emit-module-path %t/OtherActors.swiftmodule -module-name OtherActors %S/Inputs/OtherActors.swift -disable-availability-checking
3+
// RUN: %target-typecheck-verify-swift -I %t -disable-availability-checking -warn-concurrency -parse-as-library
4+
// REQUIRES: concurrency
5+
6+
actor foo {
7+
var t: Task<Void, Error>?
8+
9+
func access() {}
10+
11+
func bar() {
12+
self.t = Task {
13+
await withTaskCancellationHandler {
14+
self.access()
15+
} onCancel: { @Sendable in
16+
17+
}
18+
}
19+
}
20+
}

0 commit comments

Comments
 (0)