mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
The `Task` type has oscillated somewhat from being purely a namespace,
to having instances that are used (albeit rarely), back to purely
being a namespace that isn't used for all that many names. Many of the
names that used to be on Task have already been moved out, e.g., for
creating new detached tasks, creating new task groups, adding
cancellation handlers, etc.
Collapse `Task.Handle<Success, Failure>` into `Task<Success, Failure>`.
`Task.Handle` is the type that is most frequently referenced in the
concurrency library, so giving it the short name `Task` is most
appropriate. Replace the top-level async/detach functions with a
`Task` initializer and `Task.detached`, respectively.
The `Task` type can still act as a namespace for static operations
such as, e.g., `Task.isCancelled`. Do this with an extension of the
form:
extension Task where Success == Never, Failure == Never { ... }
We've been accruing a number of compatibility shims. Move them all
into their own source file, deprecate them, and make them
always-emit-into-client so they don't have any ABI impact.
121 lines
4.2 KiB
Swift
121 lines
4.2 KiB
Swift
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2020 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
import Swift
|
|
@_implementationOnly import _SwiftConcurrencyShims
|
|
|
|
// ==== Task Cancellation ------------------------------------------------------
|
|
|
|
/// Execute an operation with cancellation handler which will immediately be
|
|
/// invoked if the current task is cancelled.
|
|
///
|
|
/// This differs from the operation cooperatively checking for cancellation
|
|
/// and reacting to it in that the cancellation handler is _always_ and
|
|
/// _immediately_ invoked when the task is cancelled. For example, even if the
|
|
/// operation is running code which never checks for cancellation, a cancellation
|
|
/// handler still would run and give us a chance to run some cleanup code.
|
|
///
|
|
/// Does not check for cancellation, and always executes the passed `operation`.
|
|
///
|
|
/// This function returns instantly and will never suspend.
|
|
@available(SwiftStdlib 5.5, *)
|
|
public func withTaskCancellationHandler<T>(
|
|
handler: @Sendable () -> (),
|
|
operation: () async throws -> T
|
|
) async rethrows -> T {
|
|
let task = Builtin.getCurrentAsyncTask()
|
|
|
|
guard !_taskIsCancelled(task) else {
|
|
// If the current task is already cancelled, run the handler immediately.
|
|
handler()
|
|
return try await operation()
|
|
}
|
|
|
|
let record = _taskAddCancellationHandler(handler: handler)
|
|
defer { _taskRemoveCancellationHandler(record: record) }
|
|
|
|
return try await operation()
|
|
}
|
|
|
|
@available(SwiftStdlib 5.5, *)
|
|
extension Task {
|
|
/// Returns `true` if the task is cancelled, and should stop executing.
|
|
///
|
|
/// - SeeAlso: `checkCancellation()`
|
|
public var isCancelled: Bool {
|
|
withUnsafeCurrentTask { task in
|
|
guard let task = task else {
|
|
return false
|
|
}
|
|
|
|
return _taskIsCancelled(task._task)
|
|
}
|
|
}
|
|
}
|
|
|
|
@available(SwiftStdlib 5.5, *)
|
|
extension Task where Success == Never, Failure == Never {
|
|
/// Returns `true` if the task is cancelled, and should stop executing.
|
|
///
|
|
/// If no current `Task` is available, returns `false`, as outside of a task
|
|
/// context no task cancellation may be observed.
|
|
///
|
|
/// - SeeAlso: `checkCancellation()`
|
|
public static var isCancelled: Bool {
|
|
withUnsafeCurrentTask { task in
|
|
task?.isCancelled ?? false
|
|
}
|
|
}
|
|
}
|
|
|
|
@available(SwiftStdlib 5.5, *)
|
|
extension Task where Success == Never, Failure == Never {
|
|
/// Check if the task is cancelled and throw an `CancellationError` if it was.
|
|
///
|
|
/// It is intentional that no information is passed to the task about why it
|
|
/// was cancelled. A task may be cancelled for many reasons, and additional
|
|
/// reasons may accrue / after the initial cancellation (for example, if the
|
|
/// task fails to immediately exit, it may pass a deadline).
|
|
///
|
|
/// The goal of cancellation is to allow tasks to be cancelled in a
|
|
/// lightweight way, not to be a secondary method of inter-task communication.
|
|
///
|
|
/// ### Suspension
|
|
/// This function returns instantly and will never suspend.
|
|
///
|
|
/// - SeeAlso: `isCancelled()`
|
|
public static func checkCancellation() throws {
|
|
if Task<Never, Never>.isCancelled {
|
|
throw CancellationError()
|
|
}
|
|
}
|
|
|
|
/// The default cancellation thrown when a task is cancelled.
|
|
///
|
|
/// This error is also thrown automatically by `Task.checkCancellation()`,
|
|
/// if the current task has been cancelled.
|
|
public struct CancellationError: Error {
|
|
// no extra information, cancellation is intended to be light-weight
|
|
public init() {}
|
|
}
|
|
}
|
|
|
|
@available(SwiftStdlib 5.5, *)
|
|
@_silgen_name("swift_task_addCancellationHandler")
|
|
func _taskAddCancellationHandler(handler: @Sendable () -> ()) -> UnsafeRawPointer /*CancellationNotificationStatusRecord*/
|
|
|
|
@available(SwiftStdlib 5.5, *)
|
|
@_silgen_name("swift_task_removeCancellationHandler")
|
|
func _taskRemoveCancellationHandler(
|
|
record: UnsafeRawPointer /*CancellationNotificationStatusRecord*/
|
|
)
|