Skip to content

Commit 56b86b6

Browse files
authored
Merge pull request swiftlang#36766 from ktoso/wip-add-deprecated-shims-old-task-api
2 parents 927c709 + 74eee6a commit 56b86b6

File tree

4 files changed

+108
-32
lines changed

4 files changed

+108
-32
lines changed

stdlib/public/Concurrency/Task.swift

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,20 @@ extension Task {
361361

362362
// ==== Detached Tasks ---------------------------------------------------------
363363

364+
@available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *)
365+
extension Task {
366+
367+
@discardableResult
368+
@available(*, deprecated, message: "`Task.runDetached` was replaced by `detach` and will be removed shortly.")
369+
public func runDetached<T>(
370+
priority: Task.Priority = .unspecified,
371+
operation: __owned @Sendable @escaping () async throws -> T
372+
) -> Task.Handle<T, Error> {
373+
detach(priority: priority, operation: operation)
374+
}
375+
376+
}
377+
364378
/// Run given throwing `operation` as part of a new top-level task.
365379
///
366380
/// Creating detached tasks should, generally, be avoided in favor of using
@@ -536,6 +550,22 @@ extension Task {
536550

537551
// ==== UnsafeCurrentTask ------------------------------------------------------
538552

553+
@available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *)
554+
extension Task {
555+
556+
@available(*, deprecated, message: "`Task.unsafeCurrent` was replaced by `withUnsafeCurrentTask { task in ... }`, and will be removed soon.")
557+
public static var unsafeCurrent: UnsafeCurrentTask? {
558+
guard let _task = _getCurrentAsyncTask() else {
559+
return nil
560+
}
561+
// FIXME: This retain seems pretty wrong, however if we don't we WILL crash
562+
// with "destroying a task that never completed" in the task's destroy.
563+
// How do we solve this properly?
564+
_swiftRetain(_task)
565+
return UnsafeCurrentTask(_task)
566+
}
567+
}
568+
539569
/// Calls the given closure with the with the "current" task in which this
540570
/// function was invoked.
541571
///

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, *)

stdlib/public/Concurrency/TaskGroup.swift

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,24 @@ import Swift
1515

1616
// ==== TaskGroup --------------------------------------------------------------
1717

18+
@available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *)
19+
extension Task {
20+
@available(*, deprecated, message: "`Task.Group` was replaced by `ThrowingTaskGroup` and `TaskGroup` and will be removed shortly.")
21+
public typealias Group<TaskResult: Sendable> = ThrowingTaskGroup<TaskResult, Error>
22+
23+
@available(*, deprecated, message: "`Task.withGroup` was replaced by `withThrowingTaskGroup` and `withTaskGroup` and will be removed shortly.")
24+
public static func withGroup<TaskResult, BodyResult>(
25+
resultType: TaskResult.Type,
26+
returning returnType: BodyResult.Type = BodyResult.self,
27+
body: (inout Task.Group<TaskResult>) async throws -> BodyResult
28+
) async rethrows -> BodyResult {
29+
try await withThrowingTaskGroup(of: resultType) { group in
30+
try await body(&group)
31+
}
32+
}
33+
}
34+
35+
1836
/// Starts a new task group which provides a scope in which a dynamic number of
1937
/// tasks may be spawned.
2038
///
@@ -206,8 +224,19 @@ public struct TaskGroup<ChildTaskResult: Sendable> {
206224
self._task = task
207225
self._group = group
208226
}
209-
210-
/// Add a child task to the group.
227+
228+
@available(*, deprecated, message: "`Task.Group.add` has been replaced by `TaskGroup.spawn` or `TaskGroup.spawnUnlessCancelled` and will be removed shortly.")
229+
public mutating func add(
230+
priority: Task.Priority = .unspecified,
231+
operation: __owned @Sendable @escaping () async -> ChildTaskResult
232+
) async -> Bool {
233+
return try await self.spawnUnlessCancelled(priority: priority) {
234+
try! await operation()
235+
}
236+
}
237+
238+
239+
/// Add a child task to the group.
211240
///
212241
/// ### Error handling
213242
/// Operations are allowed to `throw`, in which case the `try await next()`
@@ -446,6 +475,16 @@ public struct ThrowingTaskGroup<ChildTaskResult: Sendable, Failure: Error> {
446475
self._group = group
447476
}
448477

478+
@available(*, deprecated, message: "`Task.Group.add` has been replaced by `(Throwing)TaskGroup.spawn` or `(Throwing)TaskGroup.spawnUnlessCancelled` and will be removed shortly.")
479+
public mutating func add(
480+
priority: Task.Priority = .unspecified,
481+
operation: __owned @Sendable @escaping () async throws -> ChildTaskResult
482+
) async -> Bool {
483+
return try await self.spawnUnlessCancelled(priority: priority) {
484+
try await operation()
485+
}
486+
}
487+
449488
/// Spawn, unconditionally, a child task in the group.
450489
///
451490
/// ### Error handling

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)