Skip to content

Commit 74eee6a

Browse files
committed
[Concurrency] shim for deprecated Task.withCancellationHandler
1 parent d8b4e3c commit 74eee6a

File tree

2 files changed

+37
-30
lines changed

2 files changed

+37
-30
lines changed

stdlib/public/Concurrency/TaskCancellation.swift

Lines changed: 33 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,37 @@ import Swift
1515

1616
// ==== Task Cancellation ------------------------------------------------------
1717

18+
/// Execute an operation with cancellation handler which will immediately be
19+
/// invoked if the current task is cancelled.
20+
///
21+
/// This differs from the operation cooperatively checking for cancellation
22+
/// and reacting to it in that the cancellation handler is _always_ and
23+
/// _immediately_ invoked when the task is cancelled. For example, even if the
24+
/// operation is running code which never checks for cancellation, a cancellation
25+
/// handler still would run and give us a chance to run some cleanup code.
26+
///
27+
/// Does not check for cancellation, and always executes the passed `operation`.
28+
///
29+
/// This function returns instantly and will never suspend.
30+
@available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *)
31+
public func withTaskCancellationHandler<T>(
32+
handler: @Sendable () -> (),
33+
operation: () async throws -> T
34+
) async rethrows -> T {
35+
let task = Builtin.getCurrentAsyncTask()
36+
37+
guard !_taskIsCancelled(task) else {
38+
// If the current task is already cancelled, run the handler immediately.
39+
handler()
40+
return try await operation()
41+
}
42+
43+
let record = _taskAddCancellationHandler(handler: handler)
44+
defer { _taskRemoveCancellationHandler(record: record) }
45+
46+
return try await operation()
47+
}
48+
1849
@available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *)
1950
extension Task {
2051

@@ -57,34 +88,12 @@ extension Task {
5788
}
5889
}
5990

60-
/// Execute an operation with cancellation handler which will immediately be
61-
/// invoked if the current task is cancelled.
62-
///
63-
/// This differs from the operation cooperatively checking for cancellation
64-
/// and reacting to it in that the cancellation handler is _always_ and
65-
/// _immediately_ invoked when the task is cancelled. For example, even if the
66-
/// operation is running code which never checks for cancellation, a cancellation
67-
/// handler still would run and give us a chance to run some cleanup code.
68-
///
69-
/// Does not check for cancellation, and always executes the passed `operation`.
70-
///
71-
/// This function returns instantly and will never suspend.
91+
@available(*, deprecated, message: "`Task.withCancellationHandler` has been replaced by `withTaskCancellationHandler` and will be removed shortly.")
7292
public static func withCancellationHandler<T>(
7393
handler: @Sendable () -> (),
7494
operation: () async throws -> T
7595
) async rethrows -> T {
76-
let task = Builtin.getCurrentAsyncTask()
77-
78-
guard !_taskIsCancelled(task) else {
79-
// If the current task is already cancelled, run the handler immediately.
80-
handler()
81-
return try await operation()
82-
}
83-
84-
let record = _taskAddCancellationHandler(handler: handler)
85-
defer { _taskRemoveCancellationHandler(record: record) }
86-
87-
return try await operation()
96+
try await withTaskCancellationHandler(handler: handler, operation: operation)
8897
}
8998

9099
/// The default cancellation thrown when a task is cancelled.
@@ -95,7 +104,6 @@ extension Task {
95104
// no extra information, cancellation is intended to be light-weight
96105
public init() {}
97106
}
98-
99107
}
100108

101109
@available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *)

test/Concurrency/async_cancellation.swift

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,14 @@ struct SomeFile: Sendable {
2626
}
2727

2828
@available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *)
29-
func test_cancellation_withCancellationHandler(_ anything: Any) async -> PictureData {
29+
func test_cancellation_withTaskCancellationHandler(_ anything: Any) async -> PictureData {
3030
let handle: Task.Handle<PictureData, Error> = detach {
3131
let file = SomeFile()
3232

33-
return await Task.withCancellationHandler(
34-
handler: { file.close() },
35-
operation: {
33+
return await withTaskCancellationHandler(
34+
handler: { file.close() }) {
3635
await test_cancellation_guard_isCancelled(file)
37-
})
36+
}
3837
}
3938

4039
handle.cancel()

0 commit comments

Comments
 (0)